Load packages

library(rstan)
library(cmdstanr)
options(mc.cores = parallel::detectCores())
rstan_options(auto_write = FALSE)
library(posterior)
library(bayesplot)
library(ggplot2)
library(loo)
library(latex2exp)
# library(reshape2)
# library(plyr)

Data

data <- read.csv(file="births_usa_1969.csv")
str(data)
'data.frame':   7305 obs. of  8 variables:
 $ year        : int  1969 1969 1969 1969 1969 1969 1969 1969 1969 1969 ...
 $ month       : int  1 1 1 1 1 1 1 1 1 1 ...
 $ day         : int  1 2 3 4 5 6 7 8 9 10 ...
 $ births      : int  8486 9002 9542 8960 8390 9560 9738 9734 9434 10042 ...
 $ day_of_year : int  1 2 3 4 5 6 7 8 9 10 ...
 $ day_of_week : int  3 4 5 6 7 1 2 3 4 5 ...
 $ id          : int  1 2 3 4 5 6 7 8 9 10 ...
 $ day_of_year2: int  1 2 3 4 5 6 7 8 9 10 ...

Input vector

x <- scale(data$id[], center=TRUE, scale=TRUE)

Output vector

y <- scale(data$births[], center=TRUE, scale=TRUE)

Standard deviation and mean of the output

std_y <- attr(y,"scaled:scale")
m_y <- attr(y,"scaled:center")

Standard deviation of the input

std_x <- attr(x,"scaled:scale")
std_x
[1] 2108.916

Year and week periods

period_year <- 365.25/std_x
period_week <- 7/std_x

Day of the year2 is a variable that indicates the correspondence between all the days with the days of a leap-year

day_of_year2 <- data$day_of_year2

Half range of the input domain

S <- (max(x) - min(x))/2
S
[1] 1.731695

Relationships among \(m\), \(l\) and \(c\)

  1. Relationship among the number of basis functions \(m\), the lengthscale \(l\) and the boundary factor \(c\) for a squared exponential kernel:

\[ m= 1.73 \, \frac{c}{\left(\frac{l}{S}\right)^{1.05}}, \;\;\; {\small\text{or equivalently,}} \;\;\; \frac{l}{S}= 1.68 \, \frac{c^{0.95}}{m^{0.95}}\]

with \(c \, \geq \, 0.97 + 1.45 \, \frac{l}{S}\), and \(S\) being the half range of the input domain.

  1. Relationship between \(m\) and \(l\) for a squared exponential periodic kernel:

\[m= 3.31 \, \frac{1}{l^{1.05}}, \;\;\; {\small\text{or equivalently,}} \;\;\; l= 3.12 \, \frac{1}{m^{0.95}}\]

Model

Let \(y_t\) denote the number of births on the \(t\)’th day,

\[\begin{align*} &y_{t} \sim \text{Normal}(\mu(t),\sigma^2), \\ &\mu(t) = f_1(t) + f_2(t) + f_3(t) + f_4(t) \end{align*}\]

The component \(f_1(t)\) represents the long-term trends modeled by a GP with squared exponential covariance function,

\[\begin{equation*} f_1(t) \sim \text{GP}(0,k_1), \hspace{5mm} k_1(t,t') = \alpha_1 \exp\!\!\left(\!-\frac{1}{2} \frac{(t-t')^2}{\ell_1^2}\right) \end{equation*}\]

The component \(f_2(t)\) represents the yearly smooth seasonal pattern, using a periodic squared exponential covariance function (with period 365.25 to match the average length of the year) in a GP model,

\[\begin{align*} &f_2(t) \sim \text{GP}(0,k_2), \\ &k_2(t,t') = \alpha_2 \exp\!\!\left(\!-\frac{2\,\sin^{\!2}\!(\pi(t-t')/365.25}{\ell_2^2}\right) \end{align*}\]

The component \(f_3(t)\) represents the weekly smooth pattern using a periodic squared exponential covariance function (with period 7 of length of the week) in a GP model,

\[\begin{align*} &f_3(t) \sim \text{GP}(0,k_3), \\ &k_3(t,t') = \alpha_3 \exp\!\!\left(\!-\frac{2\,\sin^{\!2}\!(\pi(t-t')/7}{\ell_3^2}\right) \end{align*}\]

The component \(f_4(t)\) represents the special days effects modeled as t-student distribution:

\[\begin{align*} &f_4(t) \sim \text{t-student}(0,\alpha_4^2), \; {\small\text{with 1 degree of freedom}},\\ &\alpha_4 \sim \text{Normal}(0,0.1) \end{align*}\]

Model in Stan code

//saved in 'stancode_def.stan'
functions {
  vector diagSPD_EQ(real gpscale, real lscale, real L, int M) {
    return sqrt((gpscale^2) * sqrt(2*pi()) * lscale * exp(-0.5*(lscale*pi()/2/L)^2 * linspaced_vector(M, 1, M)^2));
  }
  vector diagSPD_periodic(real gpscale, real lscale, int M) {
    real a = 1/lscale^2;
    int one_to_M[M];
    for (m in 1:M) one_to_M[m] = m;
    vector[M] q = sqrt(gpscale^2 * 2 / exp(a) * to_vector(modified_bessel_first_kind(one_to_M, a)));
    return append_row(q,q);
  }
  matrix PHI_EQ(int N, int M, real L, vector x) {
     matrix[N,M] PHI = sin(diag_post_multiply(rep_matrix(pi()/(2*L) * (x+L), M), linspaced_vector(M, 1, M)))/sqrt(L);
     for (m in 1:M)
       PHI[,m] = PHI[,m] - mean(PHI[,m]);
     return PHI;
  }
  matrix PHI_periodic(int N, int M, real w0, vector x) {
    matrix[N,M] mw0x = diag_post_multiply(rep_matrix(w0*x, M), linspaced_vector(M, 1, M));
    matrix[N,M] PHI = append_col(cos(mw0x), sin(mw0x));
    for (m in 1:M)
      PHI[,m] = PHI[,m] - mean(PHI[,m]);
    return PHI;
  }
}
data {
    real c_f1;                  //boundary value for function 1
    int<lower=1> M_f1;          //num basis functions for function 1
    int<lower=-1> J_f2;         //num cosine and sinu functions for function 3
    int<lower=-1> J_f3;         //num cosine and sinu functions for function 4
    int<lower=1> N;             //num observations
    vector[N] x;                //input vector
    vector[N] y;                //target vector
    real period_year;           //period of the year
    real period_week;           //period of the week
    int day_of_year2[N];        //day of the year inside a leap-year
}
transformed data {
    real L_f1= c_f1*max(fabs(x));
    //Basis functions for f1, f2 and f3
    matrix[N,M_f1] PHI_f1 = PHI_EQ(N, M_f1, L_f1, x);
    matrix[N,2*J_f2] PHI_f2 = PHI_periodic(N, J_f2, 2*pi()/period_year, x);
    matrix[N,2*J_f3] PHI_f3 = PHI_periodic(N, J_f3, 2*pi()/period_week, x);
}
parameters {
    vector[N] f;
    real intercept;
    //variables for the basis function models
    vector[M_f1] beta_f1;
    vector[2*J_f2] beta_f2;
    vector[2*J_f3] beta_f3;
    //hyperparameters
    vector<lower=0>[3] lscale;
    vector<lower=0>[3] gpscale;
    real<lower=0> noise;
    //
    //t-student prior for special days effects
    vector[366] f4;
    real<lower=0> sigma_f4;
}
transformed parameters{
    vector[N] f1;
    vector[N] f2;
    vector[N] f3;
    {
    vector[M_f1] diagSPD_f1 = diagSPD_EQ(gpscale[1], lscale[1], L_f1, M_f1);
    vector[2*J_f2] diagSPD_f2 = diagSPD_periodic(gpscale[2], lscale[2], J_f2);
    vector[2*J_f3] diagSPD_f3 = diagSPD_periodic(gpscale[3], lscale[3], J_f3);
    //
    vector[M_f1] SPD_beta_f1 = diagSPD_f1 .* beta_f1;
    vector[2*J_f2] SPD_beta_f2 = diagSPD_f2 .* beta_f2;
    vector[2*J_f3] SPD_beta_f3 = diagSPD_f3 .* beta_f3;
    //
    f1 = PHI_f1[,] * SPD_beta_f1;
    f2 = PHI_f2[,] * SPD_beta_f2;
    f3 = PHI_f3[,] * SPD_beta_f3;
    }
}
model{
    intercept ~ normal(0,1);
    beta_f1 ~ normal(0,1);
    beta_f2 ~ normal(0,1);
    beta_f3 ~ normal(0,1);
    //
    lscale ~ normal(0,2);           //GP lengthscales
    gpscale ~ normal(0,10);         //GP magnitudes
    noise ~ normal(0,1);            //model noise
    //
    //t-student prior for special days effects
    f4 ~ student_t(1, 0, sigma_f4);
    sigma_f4 ~ normal(0, 0.1);
    //
    f= intercept + f1 + f2 + f3 + f4[day_of_year2];
    target += normal_lpdf(y | f, noise);
}
generated quantities{
  vector[N] y_rep;
  vector[N] log_lik;
  for(n in 1:N){
    y_rep[n] = normal_rng(f[n], noise);
    log_lik[n] = normal_lpdf(y[n] | f[n], noise);
  }
}

User-guide for diagnosis

Assumption of the diagnosis tool:

  • Under inaccurate HSGP approximation, the estimated lengthscale \(\hat{l}\) is (always) smaller than the true lengthscale \(l\).

User-guide with the steps to perform diagnosis:

  1. Make a first guess of the lengthscale \(l^1\) of the function to be learned.

Iteration 1

  1. Obtain the minimum valid boundary factor \(c^1\) determined by the first guess \(l^1\), by using the functional relationship \(\, c^1 \, \geq \, 0.97 + 1.45 \, \frac{l^1}{S}\), where \(S\) represents the half range of the input domain.

  2. Obtain the mimimum valid number of basis functions \(m^1\) determined by \(l^1\) and \(c^1\), by using the functional relationship \(\, m^1= 1.73 \, \frac{c^1}{\left(\frac{l^1}{S}\right)^{1.05}}\). Notice that \(l^1\) can also be read as the minimum lengthscale that can be accurately fitted determined by \(m^1\) and \(c^1\) \(\left(\frac{l^1}{S}= 1.68 \, \frac{(c^1)^{0.95}}{(m^1)^{0.95}}\right)\).

  3. Fit the HSGP model and assess residuals: check any residual trends, compute rmse (Root mean square error), \(R^2\) (Coefficient of variation) and elpd (Expected log predicitve density).

  4. Check whether the estimated \(\hat{l^1}\) is equal to or greater than that \(l^1\) (the minimum lengthscale that can be accurately fitted determined by the \(m^1\) and \(c^1\) used).

  5. If the verification in step 4 is TRUE, the HSGP model approximation must be sufficiently accurate, and diagnosis ends here. Otherwise, continue with the next step 6.

Iteration 2

  1. Use the estimated lengthscale \(\hat{l^1}\) to obtain the new \(c^2\).

  2. Repeat steps 1-5 and update parameters.

Note: In order to be a bit more conservative and make as less iterations as possible to get an accurate approximation, 5 or 10 basis functions can be added to the computed \(m\) in each iteration.

Fitting and diagnosis

Initializing programming objects:

standata <- list()
fit <- list()
l_f1 <- vector()
c_f1 <- vector()
m_f1 <- vector()
l_f2 <- vector()
m_f2 <- vector()
l_f3 <- vector()
m_f3 <- vector()
l_f1_hat <- vector()
l_f2_hat <- vector()
l_f3_hat <- vector()
res <- list()
diagnosis <- list()
rmse <- vector()
eR2 <- vector()
elpd <- vector()

Iteration 1

Iteration index

i <- 1

Setting \(m\), \(l\) and \(c\)

Smooth trend function \(f_1\)

  1. Making the first guess that the lengthscale \(l\) might correspond to around 3 years (3*365=1095 days) of the input dimension
l_f1[i] <- round(1095 / std_x, 2)
l_f1[i]
[1] 0.52
  1. The boundary factor \(c\) has to fulfill \(c \, \geq \, 0.97 + 1.45 \, \frac{l}{S}\)
0.97 + 1.45*l_f1[i]/S
[1] 1.405412

Then, \(c\) is set to

c_f1[i] <- 1.5
c_f1[i]
[1] 1.5
  1. The number of basis functions \(m\) as a function of \(l\): \(\; m= 1.73 \, \frac{c}{(l/S)^{1.05}}\)
m_f1[i] <- ceiling(1.73 * c_f1[i]/(l_f1[i]/S)^1.05)
m_f1[i]
[1] 10

Yearly periodic effects function \(f_2\)

  1. Making the first guess that the lengthscale \(l\) might corresponds to half of the period of \(f_2\). So \(l=0.5\)
l_f2[i] <- 0.5
l_f2[i]
[1] 0.5
  1. Number of basis functions \(m\) as a function of \(l\): \(\; m= 3.31 \, \frac{1}{l^{1.05}}\)
m_f2[i] <-  ceiling(3.31 * 1/l_f2[i]^1.05)
m_f2[i]
[1] 7

Weekly periodic effects function \(f_3\)

  1. Making the first guess that the lengthscale \(l\) might corresponds to half of the period of \(f_3\). So \(l=0.5\)
l_f3[i] <- 0.5
l_f3[i]
[1] 0.5
  1. Number of basis functions \(m\) as a function of \(l\): \(\; m= 3.31 \, \frac{1}{l^{1.05}}\)
m_f3[i] <- ceiling(3.31 * 1/l_f3[i]^1.05)
m_f3[i]
[1] 7

Data to Stan

standata[[i]] <- list(M_f1= m_f1[i], 
                         c_f1= c_f1[i], 
                         J_f2= m_f2[i], 
                         J_f3= m_f3[i], 
                         x= x[,1], 
                         y= y[,1], 
                         N= length(x), 
                         period_year= period_year, 
                         period_week= period_week,
                         day_of_year2= day_of_year2
)
str(standata[[i]])
List of 10
 $ M_f1        : num 10
 $ c_f1        : num 1.5
 $ J_f2        : num 7
 $ J_f3        : num 7
 $ x           : num [1:7305] -1.73 -1.73 -1.73 -1.73 -1.73 ...
 $ y           : num [1:7305] -1.0316 -0.5739 -0.0949 -0.6111 -1.1168 ...
 $ N           : int 7305
 $ period_year : num 0.173
 $ period_week : num 0.00332
 $ day_of_year2: int [1:7305] 1 2 3 4 5 6 7 8 9 10 ...

Model fitting

Compiling the model

# birthday_mod <- cmdstanr::cmdstan_model(stan_file = "stancode_def.stan")

Model sampling

load("fit.rData")
# fit[[i]] <- birthday_mod$sample(data= standata[[i]], iter_warmup=200, iter_sampling=200, chains=4, thin=4, init=0.5, adapt_delta=0.9, save_warmup=FALSE)
# fit[[i]] <- read_stan_csv(fit[[i]]$output_files())

# save(fit, file="fit.rData")

Summaries of variable estimates

param = c("intercept","lscale[1]","lscale[2]","lscale[3]","gpscale[1]","gpscale[2]","gpscale[3]","noise","sigma_f4")
summary(fit[[i]], pars = param, probs = c(0.025, 0.5, 0.975), digits_summary = 4)$summary
                 mean      se_mean          sd        2.5%        50%
intercept  0.01621316 0.0004436968 0.005327212 0.005182119 0.01648965
lscale[1]  0.24056074 0.0121119972 0.153241311 0.008576415 0.23887050
lscale[2]  0.43967898 0.0105689537 0.082971748 0.221308300 0.44917800
lscale[3]  1.58862805 0.0655106390 0.613293463 0.608230400 1.48990500
gpscale[1] 2.80090466 0.1469704409 1.946717801 1.290186500 2.18231500
gpscale[2] 0.39863947 0.0113248627 0.117024120 0.236473275 0.38862950
gpscale[3] 2.81596814 0.1902765926 2.358660650 0.745981300 1.97060500
noise      0.30919913 0.0001872498 0.002675033 0.304286125 0.30911650
sigma_f4   0.02119854 0.0003020931 0.003114659 0.016262200 0.02068870
                97.5%     n_eff      Rhat
intercept  0.02563535 144.15422 0.9931835
lscale[1]  0.49549075 160.07378 0.9885406
lscale[2]  0.57091045  61.63061 1.0446003
lscale[3]  2.94770575  87.64215 1.0328162
gpscale[1] 7.51044400 175.44702 1.0021600
gpscale[2] 0.68352850 106.77876 1.0550956
gpscale[3] 8.75818300 153.65977 1.0039020
noise      0.31408470 204.08715 1.0019957
sigma_f4   0.02781466 106.30151 1.0183450

Simulation chains for the variables after warmup

traceplot(fit[[i]], pars = param, include = TRUE, unconstrain = FALSE, inc_warmup = FALSE, window = NULL, nrow = NULL, ncol = NULL)

Plot of the mean posterior function \(f_1\)

Plot of the mean posterior function \(f_2\)

Plot of the mean posterior function \(f_1 + f_2\)

Plot of the residuals

Model evaluation

Residuals

f <- summary(fit[[i]], pars = c("f"))$summary[,1]
res[[i]] <- standata[[i]]$y - f

ggplot(as.data.frame(res[[i]]), aes(res[[i]]))  +
  geom_histogram(color = 'white') +
  theme_classic()

Root mean squared error

rmse[i] <- sqrt(mean(res[[i]]^2))
rmse[i]
[1] 0.3055324

Bayesian \(R^2\) (Coefficient of determination)

noise <- as.matrix(fit[[i]], pars = c("noise"))
sd_f <- apply(as.matrix(fit[[i]], pars = c("f")), 1, sd)
R2 <- sd_f^2/(sd_f^2 + noise^2)

ggplot(as.data.frame(R2), aes(R2))  +
  geom_histogram(color = 'white') +
  theme_classic()

Median of \(R^2\)

eR2[i] <- median(R2)
eR2[i]
[1] 0.904461

Log predictive density (lpd)

lpd <- summary(fit[[i]], pars = c("log_lik"))$summary[,1]

ggplot(as.data.frame(lpd), aes(lpd))  +
  geom_histogram(color = 'white') +
  theme_classic()

Median of lpd

elpd[i] <- median(lpd)
elpd[i]
[1] 0.07947658

Diagnosis

Smooth trend function \(f_1\)

  1. Estimated lengthscale \(\hat{l}\)
l_f1_hat[i] <- round(summary(fit[[i]], pars = "lscale[1]")$summary[,1], 2)
l_f1_hat[i]
[1] 0.24
  1. Check whether \(\hat{l}\) is equal to or greater than l_f1 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f1_hat[i] >= l_f1[i]
[1] FALSE

Yearly periodic effects function \(f_2\)

  1. Estimated lengthscale \(\hat{l}\)
l_f2_hat[i] <- round(summary(fit[[i]], pars = "lscale[2]")$summary[,1], 2)
l_f2_hat[i]
[1] 0.44
  1. Check whether \(\hat{l}\) is equal to or greater than l_f2 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f2_hat[i] >= l_f2[i]
[1] FALSE

Weekly periodic effects function \(f_3\)

  1. Estimated lengthscale \(\hat{l}\)
l_f3_hat[i] <- round(summary(fit[[i]], pars = "lscale[3]")$summary[,1], 2)
l_f3_hat[i]
[1] 1.59
  1. Check whether \(\hat{l}\) is equal to or greater than l_f3 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f3_hat[i] >= l_f3[i]
[1] TRUE

Summary table

iter GP_func l c m l_hat l_hat > l rmse R2 elpd
1 f1 0.52 1.5 10 0.24 FALSE 0.306 0.904 0.079
1 f2 0.50 NA 7 0.44 FALSE 0.306 0.904 0.079
1 f3 0.50 NA 7 1.59 TRUE 0.306 0.904 0.079

Iteration 2

Iteration index

i <- 2

Setting \(m\), \(l\) and \(c\)

Smooth trend function \(f_1\)

  1. Updating \(l\) with its estimate \(\hat{l}\) in the first iteration
l_f1[i] <- l_f1_hat[i-1]
l_f1[i]
[1] 0.24
  1. The boundary factor \(c\) has to fulfill \(c \, \geq \, 0.97 + 1.45 \, \frac{l}{S}\)
0.97 + 1.45*l_f1[i]/S
[1] 1.170959

Then, \(c\) is set to

c_f1[i] <- 1.5
c_f1[i]
[1] 1.5
  1. The number of basis functions \(m\) as a function of \(l\): \(\; m= 1.73 \, \frac{c}{(l/S)^{1.05}}\)
if(1.73 * c_f1[i]/(l_f1[i]/S)^1.05 < 5) m_f1[i] <- 5 else m_f1[i] <- ceiling(1.73 * c_f1[i]/(l_f1[i]/S)^1.05)
m_f1[i]
[1] 21

Yearly periodic effects function \(f_2\)

  1. Updating \(l\) with its estimate \(\hat{l}\) in the first iteration
l_f2[i] <- l_f2_hat[i-1]
l_f2[i]
[1] 0.44
  1. Number of basis functions \(m\) as a function of \(l\): \(\; m= 3.31 \, \frac{1}{l^{1.05}}\)
if(3.31 * 1/l_f2[i]^1.05 < 5) m_f2[i] <- 5 else m_f2[i] <- ceiling( 3.31 * 1/l_f2[i]^1.05)
m_f2[i]
[1] 8

Weekly periodic effects function \(f_3\)

  1. Updating \(l\) with its estimate \(\hat{l}\) in the first iteration
l_f3[i] <- l_f3_hat[i-1]
l_f3[i]
[1] 1.59
  1. Number of basis functions \(m\) as a function of \(l\): \(\; m= 3.31 \, \frac{1}{l^{1.05}}\)
if(3.31 * 1/l_f3[i]^1.05 < 5) m_f3[i] <- 5 else m_f3[i] <- ceiling(3.31 * 1/l_f3[i]^1.05)
m_f3[i]
[1] 5

Data to Stan

standata[[i]] <- list(M_f1= m_f1[i], 
                 c_f1= c_f1[i], 
                 J_f2= m_f2[i], 
                 J_f3= m_f3[i], 
                 x= x[,1], 
                 y= y[,1], 
                 N= length(x), 
                 period_year= period_year, 
                 period_week= period_week,
                 day_of_year2= day_of_year2
)
str(standata[[i]])
List of 10
 $ M_f1        : num 21
 $ c_f1        : num 1.5
 $ J_f2        : num 8
 $ J_f3        : num 5
 $ x           : num [1:7305] -1.73 -1.73 -1.73 -1.73 -1.73 ...
 $ y           : num [1:7305] -1.0316 -0.5739 -0.0949 -0.6111 -1.1168 ...
 $ N           : int 7305
 $ period_year : num 0.173
 $ period_week : num 0.00332
 $ day_of_year2: int [1:7305] 1 2 3 4 5 6 7 8 9 10 ...

Model fitting

Compiling the model

# birthday_mod <- cmdstanr::cmdstan_model(stan_file = "stancode_def.stan")

Model sampling (using cmdstanr package)

# load("fit.rData")
# fit[[i]] <- birthday_mod$sample(data= standata[[i]], iter_warmup=200, iter_sampling=200, chains=4, thin=4, init=0.5, adapt_delta=0.9, save_warmup=FALSE)
# fit[[i]] <- rstan::read_stan_csv(fit[[i]]$output_files())

# save(fit, file="fit.rData")

Summaries of variable estimates

param = c("intercept","lscale[1]","lscale[2]","lscale[3]","gpscale[1]","gpscale[2]","gpscale[3]","noise","sigma_f4")
summary(fit[[i]], pars = param, probs = c(0.025, 0.5, 0.975), digits_summary = 4)$summary
                 mean      se_mean          sd       2.5%       50%       97.5%
intercept  0.03209490 0.0006963903 0.005952288 0.02002443 0.0324404  0.04281516
lscale[1]  0.20129869 0.0043869778 0.045159338 0.07162255 0.2089775  0.26623510
lscale[2]  0.34841957 0.0055318075 0.054283476 0.21823128 0.3536220  0.44857008
lscale[3]  1.70160588 0.0482643667 0.641194415 0.70088583 1.5790850  3.19423950
gpscale[1] 0.84056559 0.0285485120 0.330861998 0.44415168 0.7609500  1.68403925
gpscale[2] 0.34160833 0.0096154126 0.092702693 0.21751665 0.3231235  0.60874603
gpscale[3] 3.14635309 0.1900064632 2.570161204 0.77181205 2.2757550 10.69412250
noise      0.29952692 0.0001630606 0.002453281 0.29424758 0.2996545  0.30394945
sigma_f4   0.02045204 0.0004095576 0.002985429 0.01490792 0.0203633  0.02544959
               n_eff      Rhat
intercept   73.05710 1.0379945
lscale[1]  105.96545 0.9947814
lscale[2]   96.29443 1.0078471
lscale[3]  176.49249 1.0047101
gpscale[1] 134.31571 1.0031222
gpscale[2]  92.94988 1.0369656
gpscale[3] 182.97172 1.0002500
noise      226.35816 1.0050146
sigma_f4    53.13536 1.0398422

Simulation chains for the variables after warmup

traceplot(fit[[i]], pars = param, include = TRUE, unconstrain = FALSE, inc_warmup = FALSE, window = NULL, nrow = NULL, ncol = NULL)

Plot of the mean posterior function \(f_1\)

Plot of the mean posterior function \(f_2\)

Plot of the mean posterior function \(f_1 + f_2\)

Plot of the residuals

Model evaluation

Residuals

f <- summary(fit[[i]], pars = c("f"))$summary[,1]
res[[i]] <- standata[[i]]$y - f

ggplot(as.data.frame(res[[i]]), aes(res[[i]]))  +
  geom_histogram(color = 'white') +
  theme_classic()

Root mean squared error

rmse[i] <- sqrt(mean(res[[i]]^2))
rmse[i]
[1] 0.2954186

Bayesian \(R^2\) (Coefficient of determination)

noise <- as.matrix(fit[[i]], pars = c("noise"))
sd_f <- apply(as.matrix(fit[[i]], pars = c("f")), 1, sd)
R2 <- sd_f^2/(sd_f^2 + noise^2)

ggplot(as.data.frame(R2), aes(R2))  +
  geom_histogram(color = 'white') +
  theme_classic()

Median of \(R^2\)

eR2[i] <- median(R2)
eR2[i]
[1] 0.9101999

Log predictive density (lpd)

lpd <- summary(fit[[i]], pars = c("log_lik"))$summary[,1]

ggplot(as.data.frame(lpd), aes(lpd))  +
  geom_histogram(color = 'white') +
  theme_classic()

Median of lpd

elpd[i] <- median(lpd)
elpd[i]
[1] 0.1183452

Diagnosis

Smooth trend function \(f_1\)

  1. Estimated lengthscale \(\hat{l}\)
l_f1_hat[i] <- round(summary(fit[[i]], pars = "lscale[1]")$summary[,1], 2)
l_f1_hat[i]
[1] 0.2
  1. Check whether \(\hat{l}\) is equal to or greater than l_f1 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f1_hat[i] >= l_f1[i]
[1] FALSE

Yearly periodic effects function \(f_2\)

  1. Estimated lengthscale \(\hat{l}\)
l_f2_hat[i] <- round(summary(fit[[i]], pars = "lscale[2]")$summary[,1], 2)
l_f2_hat[i]
[1] 0.35
  1. Check whether \(\hat{l}\) is equal to or greater than l_f2 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f2_hat[i] >= l_f2[i]
[1] FALSE

Weekly periodic effects function \(f_3\)

  1. Estimated lengthscale \(\hat{l}\)
l_f3_hat[i] <- round(summary(fit[[i]], pars = "lscale[3]")$summary[,1], 2)
l_f3_hat[i]
[1] 1.7
  1. Check whether \(\hat{l}\) is equal to or greater than l_f3 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f3_hat[i] >= l_f3[i]
[1] TRUE

Summary table

iter GP_func l c m l_hat l_hat > l rmse R2 elpd
2 f1 0.24 1.5 21 0.20 FALSE 0.295 0.91 0.118
2 f2 0.44 NA 8 0.35 FALSE 0.295 0.91 0.118
2 f3 1.59 NA 5 1.70 TRUE 0.295 0.91 0.118

Iteration 3

Iteration index

i <- 3

Setting \(m\), \(l\) and \(c\)

Smooth trend function \(f_1\)

  1. Updating \(l\) with its estimate \(\hat{l}\) in the second iteration
l_f1[i] <- l_f1_hat[i-1]
l_f1[i]
[1] 0.2
  1. The boundary factor \(c\) has to fulfill \(c \, \geq \, 0.97 + 1.45 \, \frac{l}{S}\)
0.97 + 1.45*l_f1[i]/S
[1] 1.137466

Then, \(c\) is set to

c_f1[i] <- 1.5
c_f1[i]
[1] 1.5
  1. The number of basis functions \(m\) as a function of \(l\): \(\; m= 1.73 \, \frac{c}{(l/S)^{1.05}}\)
if(1.73 * c_f1[i]/(l_f1[i]/S)^1.05 < 5) m_f1[i] <- 5 else m_f1[i] <- ceiling(1.73 * c_f1[i]/(l_f1[i]/S)^1.05)
m_f1[i]
[1] 26

Yearly periodic effects function \(f_2\)

  1. Updating \(l\) with its estimate \(\hat{l}\) in the second iteration
l_f2[i] <- l_f2_hat[i-1]
l_f2[i]
[1] 0.35
  1. Number of basis functions \(m\) as a function of \(l\): \(\; m= 3.31 \, \frac{1}{l^{1.05}}\)
if(3.31 * 1/l_f2[i]^1.05 < 5) m_f2[i] <- 5 else m_f2[i] <- ceiling(3.31 * 1/l_f2[i]^1.05)
m_f2[i]
[1] 10

Weekly periodic effects function \(f_3\)

  1. Updating \(l\) with its estimate \(\hat{l}\) in the second iteration
l_f3[i] <- l_f3_hat[i-1]
l_f3[i]
[1] 1.7
  1. Number of basis functions \(m\) as a function of \(l\): \(\; m= 3.31 \, \frac{1}{l^{1.05}}\)
if(3.31 * 1/l_f3[i]^1.05 < 5) m_f3[i] <- 5 else m_f3[i] <- ceiling(3.31 * 1/l_f3[i]^1.05)
m_f3[i]
[1] 5

Data to Stan

standata[[i]] <- list(M_f1= m_f1[i], 
                 c_f1= c_f1[i], 
                 J_f2= m_f2[i], 
                 J_f3= m_f3[i], 
                 x= x[,1], 
                 y= y[,1], 
                 N= length(x), 
                 period_year= period_year, 
                 period_week= period_week,
                 day_of_year2= day_of_year2
)
str(standata[[i]])
List of 10
 $ M_f1        : num 26
 $ c_f1        : num 1.5
 $ J_f2        : num 10
 $ J_f3        : num 5
 $ x           : num [1:7305] -1.73 -1.73 -1.73 -1.73 -1.73 ...
 $ y           : num [1:7305] -1.0316 -0.5739 -0.0949 -0.6111 -1.1168 ...
 $ N           : int 7305
 $ period_year : num 0.173
 $ period_week : num 0.00332
 $ day_of_year2: int [1:7305] 1 2 3 4 5 6 7 8 9 10 ...

Model fitting

Compiling the model

# birthday_mod <- cmdstanr::cmdstan_model(stan_file = "stancode_def.stan")

Model sampling

# load("fit.rData")
# fit[[i]] <- birthday_mod$sample(data= standata[[i]], iter_warmup=200, iter_sampling=200, chains=4, thin=4, init=0.5, adapt_delta=0.9, save_warmup=FALSE)
# fit[[i]] <- rstan::read_stan_csv(fit[[i]]$output_files())

# save(fit, file="fit.rData")

Summaries of variable estimates

param = c("intercept","lscale[1]","lscale[2]","lscale[3]","gpscale[1]","gpscale[2]","gpscale[3]","noise","sigma_f4")
summary(fit[[i]], pars = param, probs = c(0.025, 0.5, 0.975), digits_summary = 4)$summary
                 mean      se_mean          sd       2.5%        50%      97.5%
intercept  0.02351247 0.0005943055 0.004968132 0.01406945 0.02367795 0.03283830
lscale[1]  0.13123223 0.0066514750 0.052912420 0.00864844 0.14233000 0.20619690
lscale[2]  0.29457215 0.0027172111 0.031269295 0.23831755 0.29434700 0.35713853
lscale[3]  1.57049730 0.0544457001 0.642421873 0.49599778 1.51369500 2.83534325
gpscale[1] 0.90058899 0.0908635474 0.566716049 0.53282395 0.75180300 2.20484175
gpscale[2] 0.32634141 0.0067091670 0.073006389 0.21944840 0.31186150 0.51495445
gpscale[3] 2.96833263 0.1920584568 2.474883866 0.69133465 2.05472500 8.99802925
noise      0.29703793 0.0001877659 0.002682057 0.29178015 0.29692300 0.30235395
sigma_f4   0.01585057 0.0003702678 0.002837476 0.01091628 0.01561165 0.02172783
               n_eff      Rhat
intercept   69.88221 1.0264599
lscale[1]   63.28187 1.0210061
lscale[2]  132.43093 1.0198239
lscale[3]  139.22379 1.0266769
gpscale[1]  38.90018 1.0952120
gpscale[2] 118.40895 1.0111913
gpscale[3] 166.05149 1.0048522
noise      204.03411 0.9948262
sigma_f4    58.72630 1.0220584

Simulation chains for the variables after warmup

traceplot(fit[[i]], pars = param, include = TRUE, unconstrain = FALSE, inc_warmup = FALSE, window = NULL, nrow = NULL, ncol = NULL)

Plot of the mean posterior function \(f_1\)

Plot of the mean posterior function \(f_2\)

Plot of the mean posterior function \(f_1 + f_2\)

Plot of the residuals

Model evaluation

Residuals

f <- summary(fit[[i]], pars = c("f"))$summary[,1]
res[[i]] <- standata[[i]]$y - f

ggplot(as.data.frame(res[[i]]), aes(res[[i]]))  +
  geom_histogram(color = 'white') +
  theme_classic()

Root mean squared error

rmse[i] <- sqrt(mean(res[[i]]^2))
rmse[i]
[1] 0.2932521

Bayesian \(R^2\) (Coefficient of determination)

noise <- as.matrix(fit[[i]], pars = c("noise"))
sd_f <- apply(as.matrix(fit[[i]], pars = c("f")), 1, sd)
R2 <- sd_f^2/(sd_f^2 + noise^2)

ggplot(as.data.frame(R2), aes(R2))  +
  geom_histogram(color = 'white') +
  theme_classic()

Median of \(R^2\)

eR2[i] <- median(R2)
eR2[i]
[1] 0.9118072

Log predictive density (lpd)

lpd <- summary(fit[[i]], pars = c("log_lik"))$summary[,1]

ggplot(as.data.frame(lpd), aes(lpd))  +
  geom_histogram(color = 'white') +
  theme_classic()

Median of lpd

elpd[i] <- median(lpd)
elpd[i]
[1] 0.1315323

Diagnosis

Smooth trend function \(f_1\)

  1. Estimated lengthscale \(\hat{l}\)
l_f1_hat[i] <- round(summary(fit[[i]], pars = "lscale[1]")$summary[,1], 2)
l_f1_hat[i]
[1] 0.13
  1. Check whether \(\hat{l}\) is equal to or greater than l_f1 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f1_hat[i] >= l_f1[i]
[1] FALSE

Yearly periodic effects function \(f_2\)

  1. Estimated lengthscale \(\hat{l}\)
l_f2_hat[i] <- round(summary(fit[[i]], pars = "lscale[2]")$summary[,1], 2)
l_f2_hat[i]
[1] 0.29
  1. Check whether \(\hat{l}\) is equal to or greater than l_f2 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f2_hat[i] >= l_f2[i]
[1] FALSE

Weekly periodic effects function \(f_3\)

  1. Estimated lengthscale \(\hat{l}\)
l_f3_hat[i] <- round(summary(fit[[i]], pars = "lscale[3]")$summary[,1], 2)
l_f3_hat[i]
[1] 1.57
  1. Check whether \(\hat{l}\) is equal to or greater than l_f3 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f3_hat[i] >= l_f3[i]
[1] FALSE

Summary table

iter GP_func l c m l_hat l_hat > l rmse R2 elpd
3 f1 0.20 1.5 26 0.13 FALSE 0.293 0.912 0.132
3 f2 0.35 NA 10 0.29 FALSE 0.293 0.912 0.132
3 f3 1.70 NA 5 1.57 FALSE 0.293 0.912 0.132

Iteration 4

Iteration index

i <- 4

Setting \(m\), \(l\) and \(c\)

Smooth trend function \(f_1\)

  1. Updating \(l\) with its estimate \(\hat{l}\) in the third iteration
l_f1[i] <- l_f1_hat[i-1]
l_f1[i]
[1] 0.13
  1. The boundary factor \(c\) has to fulfill \(c \, \geq \, 0.97 + 1.45 \, \frac{l}{S}\)
0.97 + 1.45*l_f1[i]/S
[1] 1.078853

Then, \(c\) is set to

c_f1[i] <- 1.5
c_f1[i]
[1] 1.5
  1. The number of basis functions \(m\) as a function of \(l\): \(\; m= 1.73 \, \frac{c}{(l/S)^{1.05}}\)
if(1.73 * c_f1[i]/(l_f1[i]/S)^1.05 < 5) m_f1[i] <- 5 else m_f1[i] <- ceiling(1.73 * c_f1[i]/(l_f1[i]/S)^1.05)
m_f1[i]
[1] 40

Yearly periodic effects function \(f_2\)

  1. Updating \(l\) with its estimate \(\hat{l}\) in the third iteration
l_f2[i] <- l_f2_hat[i-1]
l_f2[i]
[1] 0.29
  1. Number of basis functions \(m\) as a function of \(l\): \(\; m= 3.31 \, \frac{1}{l^{1.05}}\)
if(3.31 * 1/l_f2[i]^1.05 < 5) m_f2[i] <- 5 else m_f2[i] <- ceiling(3.31 * 1/l_f2[i]^1.05)
m_f2[i]
[1] 13

Weekly periodic effects function \(f_3\)

  1. Updating \(l\) with its estimate \(\hat{l}\) in the third iteration
l_f3[i] <- l_f3_hat[i-1]
l_f3[i]
[1] 1.57
  1. Number of basis functions \(m\) as a function of \(l\): \(\; m= 3.31 \, \frac{1}{l^{1.05}}\)
if(3.31 * 1/l_f3[i]^1.05 < 5) m_f3[i] <- 5 else m_f3[i] <- ceiling(3.31 * 1/l_f3[i]^1.05)
m_f3[i]
[1] 5

Data to Stan

standata[[i]] <- list(M_f1= m_f1[i], 
                 c_f1= c_f1[i], 
                 J_f2= m_f2[i], 
                 J_f3= m_f3[i], 
                 x= x[,1], 
                 y= y[,1], 
                 N= length(x), 
                 period_year= period_year, 
                 period_week= period_week,
                 day_of_year2= day_of_year2
)
str(standata[[i]])
List of 10
 $ M_f1        : num 40
 $ c_f1        : num 1.5
 $ J_f2        : num 13
 $ J_f3        : num 5
 $ x           : num [1:7305] -1.73 -1.73 -1.73 -1.73 -1.73 ...
 $ y           : num [1:7305] -1.0316 -0.5739 -0.0949 -0.6111 -1.1168 ...
 $ N           : int 7305
 $ period_year : num 0.173
 $ period_week : num 0.00332
 $ day_of_year2: int [1:7305] 1 2 3 4 5 6 7 8 9 10 ...

Model fitting

Compiling the model

# birthday_mod <- cmdstanr::cmdstan_model(stan_file = "stancode_def.stan")

Model sampling

# load("fit.rData")
# fit[[i]] <- birthday_mod$sample(data= standata[[i]], iter_warmup=200, iter_sampling=200, chains=4, thin=4, init=0.5, adapt_delta=0.9, save_warmup=FALSE)
# fit[[i]] <- rstan::read_stan_csv(fit[[i]]$output_files())

# save(fit, file="fit.rData")

Summaries of variable estimates

param = c("intercept","lscale[1]","lscale[2]","lscale[3]","gpscale[1]","gpscale[2]","gpscale[3]","noise","sigma_f4")
summary(fit[[i]], pars = param, probs = c(0.025, 0.5, 0.975), digits_summary = 4)$summary
                 mean      se_mean          sd        2.5%       50%      97.5%
intercept  0.02163107 0.0003909226 0.004592181 0.011938308 0.0215220 0.03002273
lscale[1]  0.16195171 0.0010754892 0.013771676 0.133884550 0.1614695 0.19024127
lscale[2]  0.24561287 0.0024693364 0.028699315 0.181404650 0.2468775 0.29111728
lscale[3]  1.64165354 0.0552050194 0.636731523 0.516088400 1.5913050 2.98496650
gpscale[1] 0.62111567 0.0121793670 0.154971086 0.416687025 0.5857125 0.97306960
gpscale[2] 0.31635318 0.0067557442 0.061739874 0.218932425 0.3028695 0.47106488
gpscale[3] 3.01882210 0.2310811166 2.396089857 0.745482025 2.3385300 8.75506500
noise      0.29271492 0.0001838906 0.002583868 0.287375825 0.2928455 0.29797135
sigma_f4   0.01465976 0.0007576488 0.002767662 0.009466402 0.0144705 0.02018042
               n_eff      Rhat
intercept  137.99281 0.9992550
lscale[1]  163.96889 0.9869280
lscale[2]  135.07735 1.0386769
lscale[3]  133.03183 1.0004049
gpscale[1] 161.90189 0.9946525
gpscale[2]  83.51896 1.0225895
gpscale[3] 107.51704 1.0053584
noise      197.43379 1.0274909
sigma_f4    13.34413 1.2271513

Simulation chains for the variables after warmup

traceplot(fit[[i]], pars = param, include = TRUE, unconstrain = FALSE, inc_warmup = FALSE, window = NULL, nrow = NULL, ncol = NULL)

Plot of the mean posterior function \(f_1\)

Plot of the mean posterior function \(f_2\)

Plot of the mean posterior function \(f_1 + f_2\)

Plot of the residuals

Model evaluation

Residuals

f <- summary(fit[[i]], pars = c("f"))$summary[,1]
res[[i]] <- standata[[i]]$y - f

ggplot(as.data.frame(res[[i]]), aes(res[[i]]))  +
  geom_histogram(color = 'white') +
  theme_classic()

Root mean squared error

rmse[i] <- sqrt(mean(res[[i]]^2))
rmse[i]
[1] 0.2893248

Bayesian \(R^2\) (Coefficient of determination)

noise <- as.matrix(fit[[i]], pars = c("noise"))
sd_f <- apply(as.matrix(fit[[i]], pars = c("f")), 1, sd)
R2 <- sd_f^2/(sd_f^2 + noise^2)

ggplot(as.data.frame(R2), aes(R2))  +
  geom_histogram(color = 'white') +
  theme_classic()

Median of \(R^2\)

eR2[i] <- median(R2)
eR2[i]
[1] 0.9142275

Log predictive density (lpd)

lpd <- summary(fit[[i]], pars = c("log_lik"))$summary[,1]

ggplot(as.data.frame(lpd), aes(lpd))  +
  geom_histogram(color = 'white') +
  theme_classic()

Median of lpd

elpd[i] <- median(lpd)
elpd[i]
[1] 0.1487322

Diagnosis

Smooth trend function \(f_1\)

  1. Estimated lengthscale \(\hat{l}\)
l_f1_hat[i] <- round(summary(fit[[i]], pars = "lscale[1]")$summary[,1], 2)
l_f1_hat[i]
[1] 0.16
  1. Check whether \(\hat{l}\) is equal to or greater than l_f1 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f1_hat[i] >= l_f1[i]
[1] TRUE

Yearly periodic effects function \(f_2\)

  1. Estimated lengthscale \(\hat{l}\)
l_f2_hat[i] <- round(summary(fit[[i]], pars = "lscale[2]")$summary[,1], 2)
l_f2_hat[i]
[1] 0.25
  1. Check whether \(\hat{l}\) is equal to or greater than l_f2 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f2_hat[i] >= l_f2[i]
[1] FALSE

Weekly periodic effects function \(f_3\)

  1. Estimated lengthscale \(\hat{l}\)
l_f3_hat[i] <- round(summary(fit[[i]], pars = "lscale[3]")$summary[,1], 2)
l_f3_hat[i]
[1] 1.64
  1. Check whether \(\hat{l}\) is equal to or greater than l_f3 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f3_hat[i] >= l_f3[i]
[1] TRUE

Summary table

iter GP_func l c m l_hat l_hat > l rmse R2 elpd
4 f1 0.13 1.5 40 0.16 TRUE 0.289 0.914 0.149
4 f2 0.29 NA 13 0.25 FALSE 0.289 0.914 0.149
4 f3 1.57 NA 5 1.64 TRUE 0.289 0.914 0.149

Iteration 5

Iteration index

i <- 5

Setting \(m\), \(l\) and \(c\)

Smooth trend function \(f_1\)

  1. Updating \(l\) with its estimate \(\hat{l}\) in the fourth iteration
l_f1[i] <- l_f1_hat[i-1]
l_f1[i]
[1] 0.16
  1. The boundary factor \(c\) has to fulfill \(c \, \geq \, 0.97 + 1.45 \, \frac{l}{S}\)
0.97 + 1.45*l_f1[i]/S
[1] 1.103973

Then, \(c\) is set to

c_f1[i] <- 1.5
c_f1[i]
[1] 1.5
  1. The number of basis functions \(m\) as a function of \(l\): \(\; m= 1.73 \, \frac{c}{(l/S)^{1.05}}\)
if(1.73 * c_f1[i]/(l_f1[i]/S)^1.05 < 5) m_f1[i] <- 5 else m_f1[i] <- ceiling(1.73 * c_f1[i]/(l_f1[i]/S)^1.05)

m_f1[i]
[1] 32

Yearly periodic effects function \(f_2\)

  1. Updating \(l\) with its estimate \(\hat{l}\) in the third iteration
l_f2[i] <- l_f2_hat[i-1]
l_f2[i]
[1] 0.25
  1. Number of basis functions \(m\) as a function of \(l\): \(\; m= 3.31 \, \frac{1}{l^{1.05}}\)
if(3.31 * 1/l_f2[i]^1.05 < 5) m_f2[i] <- 5 else m_f2[i] <- ceiling(3.31 * 1/l_f2[i]^1.05);
m_f2[i]
[1] 15

Weekly periodic effects function \(f_3\)

  1. Updating \(l\) with its estimate \(\hat{l}\) in the fourth iteration
l_f3[i] <- l_f3_hat[i-1]
l_f3[i]
[1] 1.64
  1. Number of basis functions \(m\) as a function of \(l\): \(\, m= 3.31 \, \frac{1}{l^{1.05}}\)
if(3.31 * 1/l_f3[i]^1.05 < 5) m_f3[i] <- 5 else m_f3[i] <- ceiling(3.31 * 1/l_f3[i]^1.05)
m_f3[i]
[1] 5

Data to Stan

standata[[i]] <- list(M_f1= m_f1[i], 
                 c_f1= c_f1[i], 
                 J_f2= m_f2[i], 
                 J_f3= m_f3[i], 
                 x= x[,1], 
                 y= y[,1], 
                 N= length(x), 
                 period_year= period_year, 
                 period_week= period_week,
                 day_of_year2= day_of_year2
)
str(standata[[i]])
List of 10
 $ M_f1        : num 32
 $ c_f1        : num 1.5
 $ J_f2        : num 15
 $ J_f3        : num 5
 $ x           : num [1:7305] -1.73 -1.73 -1.73 -1.73 -1.73 ...
 $ y           : num [1:7305] -1.0316 -0.5739 -0.0949 -0.6111 -1.1168 ...
 $ N           : int 7305
 $ period_year : num 0.173
 $ period_week : num 0.00332
 $ day_of_year2: int [1:7305] 1 2 3 4 5 6 7 8 9 10 ...

Model fitting

Compiling the model

# birthday_mod <- cmdstanr::cmdstan_model(stan_file = "stancode_def.stan")

Model sampling

# load("fit.rData")
# fit[[i]] <- birthday_mod$sample(data= standata[[i]], iter_warmup=200, iter_sampling=200, chains=4, thin=4, init=0.5, adapt_delta=0.9, save_warmup=FALSE)
# fit[[i]] <- rstan::read_stan_csv(fit[[i]]$output_files())

# save(fit, file="fit.rData")

Summaries of variable estimates

param = c("intercept","lscale[1]","lscale[2]","lscale[3]","gpscale[1]","gpscale[2]","gpscale[3]","noise","sigma_f4")
summary(fit[[i]], pars = param, probs = c(0.025, 0.5, 0.975), digits_summary = 4)$summary
                 mean      se_mean          sd       2.5%        50%
intercept  0.02279584 0.0005675383 0.004899672 0.01377460 0.02295105
lscale[1]  0.16321279 0.0012264089 0.016537237 0.12621907 0.16452300
lscale[2]  0.22884513 0.0024885582 0.021755035 0.18737257 0.22838250
lscale[3]  1.78115501 0.0484845953 0.621830253 0.73027560 1.74175500
gpscale[1] 0.62287706 0.0104260516 0.142880281 0.43168012 0.59825100
gpscale[2] 0.29488222 0.0048951827 0.055301127 0.21142265 0.28873300
gpscale[3] 3.63075626 0.2139917502 2.737805014 0.72485948 2.59414000
noise      0.29303347 0.0001938712 0.002414114 0.28847757 0.29308650
sigma_f4   0.01280845 0.0003352905 0.002444182 0.00896321 0.01251480
                 97.5%     n_eff      Rhat
intercept   0.03294064  74.53218 1.0714969
lscale[1]   0.19295540 181.82570 1.0068069
lscale[2]   0.27628600  76.42298 1.0651080
lscale[3]   3.06536775 164.48873 1.0029784
gpscale[1]  0.95707893 187.80400 0.9938507
gpscale[2]  0.43470313 127.62335 1.0243951
gpscale[3] 10.83963750 163.68579 1.0195254
noise       0.29736762 155.05609 1.0005674
sigma_f4    0.01857094  53.14037 1.0729330

Simulation chains for the variables after warmup

traceplot(fit[[i]], pars = param, include = TRUE, unconstrain = FALSE, inc_warmup = FALSE, window = NULL, nrow = NULL, ncol = NULL)

Plot of the mean posterior function \(f_1\)

Plot of the mean posterior function \(f_2\)

Plot of the mean posterior function \(f_1 + f_2\)

Plot of the residuals

Model evaluation

Residuals

f <- summary(fit[[i]], pars = c("f"))$summary[,1]
res[[i]] <- standata[[i]]$y - f

ggplot(as.data.frame(res[[i]]), aes(res[[i]]))  +
  geom_histogram(color = 'white') +
  theme_classic()

Root mean squared error

rmse[i] <- sqrt(mean(res[[i]]^2))
rmse[i]
[1] 0.2895321

Bayesian \(R^2\) (Coefficient of determination)

noise <- as.matrix(fit[[i]], pars = c("noise"))
sd_f <- apply(as.matrix(fit[[i]], pars = c("f")), 1, sd)
R2 <- sd_f^2/(sd_f^2 + noise^2)

ggplot(as.data.frame(R2), aes(R2))  +
  geom_histogram(color = 'white') +
  theme_classic()

Median of \(R^2\)

eR2[i] <- median(R2)
eR2[i]
[1] 0.9140058

Log predictive density (lpd)

lpd <- summary(fit[[i]], pars = c("log_lik"))$summary[,1]

ggplot(as.data.frame(lpd), aes(lpd))  +
  geom_histogram(color = 'white') +
  theme_classic()

Median of lpd

elpd[i] <- median(lpd)
elpd[i]
[1] 0.1497226

Diagnosis

Smooth trend function \(f_1\)

  1. Estimated lengthscale \(\hat{l}\)
l_f1_hat[i] <- round(summary(fit[[i]], pars = "lscale[1]")$summary[,1], 2)
l_f1_hat[i]
[1] 0.16
  1. Check whether \(\hat{l}\) is equal to or greater than l_f1 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f1_hat[i] >= l_f1[i]
[1] TRUE

Yearly periodic effects function \(f_2\)

  1. Estimated lengthscale \(\hat{l}\)
l_f2_hat[i] <- round(summary(fit[[i]], pars = "lscale[2]")$summary[,1], 2)
l_f2_hat[i]
[1] 0.23
  1. Check whether \(\hat{l}\) is equal to or greater than l_f2 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f2_hat[i] >= l_f2[i]
[1] FALSE

Weekly periodic effects function \(f_3\)

  1. Estimated lengthscale \(\hat{l}\)
l_f3_hat[i] <- round(summary(fit[[i]], pars = "lscale[3]")$summary[,1], 2)
l_f3_hat[i]
[1] 1.78
  1. Check whether \(\hat{l}\) is equal to or greater than l_f3 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f3_hat[i] >= l_f3[i]
[1] TRUE

Summary table

iter GP_func l c m l_hat l_hat > l rmse R2 elpd
5 f1 0.16 1.5 32 0.16 TRUE 0.29 0.914 0.15
5 f2 0.25 NA 15 0.23 FALSE 0.29 0.914 0.15
5 f3 1.64 NA 5 1.78 TRUE 0.29 0.914 0.15

Iteration 6

Iteration index

i <- 6

Setting \(m\), \(l\) and \(c\)

Smooth trend function \(f_1\)

  1. Updating \(l\) with its estimate \(\hat{l}\) in the fifth iteration
l_f1[i] <- l_f1_hat[i-1]
l_f1[i]
[1] 0.16
  1. The boundary factor \(c\) has to fulfill \(c \, \geq \, 0.97 + 1.45 \, \frac{l}{S}\)
0.97 + 1.45*l_f1[i]/S
[1] 1.103973

Then, \(c\) is set to

c_f1[i] <- 1.5
c_f1[i]
[1] 1.5
  1. The number of basis functions \(m\) as a function of \(l\): \(\; m= 1.73 \, \frac{c}{(l/S)^{1.05}}\)
if(1.73 * c_f1[i]/(l_f1[i]/S)^1.05 < 5) m_f1[i] <- 5 else m_f1[i] <- ceiling(1.73 * c_f1[i]/(l_f1[i]/S)^1.05)
m_f1[i]
[1] 32

Yearly periodic effects function \(f_2\)

  1. Updating \(l\) with its estimate \(\hat{l}\) in the fifth iteration
l_f2[i] <- l_f2_hat[i-1]
l_f2[i]
[1] 0.23
  1. Number of basis functions \(m\) as a function of \(l\): \(\; m= 3.31 \, \frac{1}{l^{1.05}}\)
if(3.31 * 1/l_f2[i]^1.05 < 5) m_f2[i] <- 5 else m_f2[i] <- ceiling(3.31 * 1/l_f2[i]^1.05)
m_f2[i]
[1] 16

Weekly periodic effects function \(f_3\)

  1. Updating \(l\) with its estimate \(\hat{l}\) in the fifth iteration
l_f3[i] <- l_f3_hat[i-1]
l_f3[i]
[1] 1.78
  1. Number of basis functions \(m\) as a function of \(l\): \(\; m= 3.31 \, \frac{1}{l^{1.05}}\)
if(3.31 * 1/l_f3[i]^1.05 < 5) m_f3[i] <- 5 else m_f3[i] <- ceiling(3.31 * 1/l_f3[i]^1.05)
m_f3[i]
[1] 5

Data to Stan

standata[[i]] <- list(M_f1= m_f1[i], 
                 c_f1= c_f1[i], 
                 J_f2= m_f2[i], 
                 J_f3= m_f3[i], 
                 x= x[,1], 
                 y= y[,1], 
                 N= length(x), 
                 period_year= period_year, 
                 period_week= period_week,
                 day_of_year2= day_of_year2
)
str(standata[[i]])
List of 10
 $ M_f1        : num 32
 $ c_f1        : num 1.5
 $ J_f2        : num 16
 $ J_f3        : num 5
 $ x           : num [1:7305] -1.73 -1.73 -1.73 -1.73 -1.73 ...
 $ y           : num [1:7305] -1.0316 -0.5739 -0.0949 -0.6111 -1.1168 ...
 $ N           : int 7305
 $ period_year : num 0.173
 $ period_week : num 0.00332
 $ day_of_year2: int [1:7305] 1 2 3 4 5 6 7 8 9 10 ...

Model fitting

Compiling the model

# birthday_mod <- cmdstanr::cmdstan_model(stan_file = "stancode_def.stan")

Model sampling

# load("fit.rData")
# fit[[i]] <- birthday_mod$sample(data= standata[[i]], iter_warmup=200, iter_sampling=200, chains=4, thin=4, init=0.5, adapt_delta=0.9, save_warmup=FALSE)
# fit[[i]] <- rstan::read_stan_csv(fit[[i]]$output_files())

# save(fit, file="fit.rData")

Summaries of variable estimates

param = c("intercept","lscale[1]","lscale[2]","lscale[3]","gpscale[1]","gpscale[2]","gpscale[3]","noise","sigma_f4")
summary(fit[[i]], pars = param, probs = c(0.025, 0.5, 0.975), digits_summary = 4)$summary
                 mean      se_mean          sd        2.5%        50%
intercept  0.02294053 0.0004648112 0.005550149 0.013452927 0.02243810
lscale[1]  0.16117096 0.0012463943 0.016428119 0.124791725 0.16174750
lscale[2]  0.23273374 0.0017141776 0.020520817 0.196417325 0.23225950
lscale[3]  1.64564855 0.0541690077 0.644079224 0.618704450 1.61698500
gpscale[1] 0.58483434 0.0120735964 0.131891179 0.411753125 0.56481850
gpscale[2] 0.30437833 0.0042693583 0.051882474 0.223969375 0.29740400
gpscale[3] 3.16641534 0.2283539921 2.821447927 0.656188800 2.26845000
noise      0.29283316 0.0001855130 0.002660376 0.287663800 0.29305100
sigma_f4   0.01399103 0.0004748107 0.002561988 0.009126358 0.01402015
                97.5%     n_eff      Rhat
intercept  0.03383408 142.57918 0.9886644
lscale[1]  0.19031025 173.72597 1.0078613
lscale[2]  0.27478578 143.31039 1.0149307
lscale[3]  3.11322025 141.37637 1.0113828
gpscale[1] 0.88167815 119.33235 1.0145168
gpscale[2] 0.43783017 147.67812 1.0041472
gpscale[3] 9.64981850 152.66056 1.0196156
noise      0.29808180 205.65415 0.9916026
sigma_f4   0.01883736  29.11475 1.1056103

Simulation chains for the variables after warmup

traceplot(fit[[i]], pars = param, include = TRUE, unconstrain = FALSE, inc_warmup = FALSE, window = NULL, nrow = NULL, ncol = NULL)

Plot of the mean posterior function \(f_1\)

Plot of the mean posterior function \(f_2\)

Plot of the mean posterior function \(f_1 + f_2\)

Plot of the residuals

Model evaluation

Residuals

f <- summary(fit[[i]], pars = c("f"))$summary[,1]
res[[i]] <- standata[[i]]$y - f

ggplot(as.data.frame(res[[i]]), aes(res[[i]]))  +
  geom_histogram(color = 'white') +
  theme_classic()

Root mean squared error

rmse[i] <- sqrt(mean(res[[i]]^2))
rmse[i]
[1] 0.2893593

Bayesian \(R^2\) (Coefficient of determination)

noise <- as.matrix(fit[[i]], pars = c("noise"))
sd_f <- apply(as.matrix(fit[[i]], pars = c("f")), 1, sd)
R2 <- sd_f^2/(sd_f^2 + noise^2)

ggplot(as.data.frame(R2), aes(R2))  +
  geom_histogram(color = 'white') +
  theme_classic()

Median of \(R^2\)

eR2[i] <- median(R2)
eR2[i]
[1] 0.9142495

Log predictive density (lpd)

lpd <- summary(fit[[i]], pars = c("log_lik"))$summary[,1]

ggplot(as.data.frame(lpd), aes(lpd))  +
  geom_histogram(color = 'white') +
  theme_classic()

Median of lpd

elpd[i] <- median(lpd)
elpd[i]
[1] 0.1472021

Diagnosis

Smooth trend function \(f_1\)

  1. Estimated lengthscale \(\hat{l}\)
l_f1_hat[i] <- round(summary(fit[[i]], pars = "lscale[1]")$summary[,1], 2)
l_f1_hat[i]
[1] 0.16
  1. Check whether \(\hat{l}\) is equal to or greater than l_f1 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f1_hat[i] >= l_f1[i]
[1] TRUE

Yearly periodic effects function \(f_2\)

  1. Estimated lengthscale \(\hat{l}\)
l_f2_hat[i] <- round(summary(fit[[i]], pars = "lscale[2]")$summary[,1], 2)
l_f2_hat[i]
[1] 0.23
  1. Check whether \(\hat{l}\) is equal to or greater than l_f2 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f2_hat[i] >= l_f2[i]
[1] TRUE

Weekly periodic effects function \(f_3\)

  1. Estimated lengthscale \(\hat{l}\)
l_f3_hat[i] <- round(summary(fit[[i]], pars = "lscale[3]")$summary[,1], 2)
l_f3_hat[i]
[1] 1.65
  1. Check whether \(\hat{l}\) is equal to or greater than l_f3 (the minimum \(l\) that can be accurately fitted determined by the \(m\) used)
l_f3_hat[i] >= l_f3[i]
[1] FALSE

Summary table

iter GP_func l c m l_hat l_hat > l rmse R2 elpd
6 f1 0.16 1.5 32 0.16 TRUE 0.289 0.914 0.147
6 f2 0.23 NA 16 0.23 TRUE 0.289 0.914 0.147
6 f3 1.78 NA 5 1.65 FALSE 0.289 0.914 0.147

Global summary of the diagnosis (with all iterations)

iter GP_func l c m l_hat l_hat > l rmse R2 elpd
1 1 f1 0.52 1.5 10 0.24 FALSE 0.306 0.904 0.079
4 2 f1 0.24 1.5 21 0.20 FALSE 0.295 0.910 0.118
7 3 f1 0.20 1.5 26 0.13 FALSE 0.293 0.912 0.132
10 4 f1 0.13 1.5 40 0.16 TRUE 0.289 0.914 0.149
13 5 f1 0.16 1.5 32 0.16 TRUE 0.290 0.914 0.150
16 6 f1 0.16 1.5 32 0.16 TRUE 0.289 0.914 0.147
iter GP_func l c m l_hat l_hat > l rmse R2 elpd
2 1 f2 0.50 NA 7 0.44 FALSE 0.306 0.904 0.079
5 2 f2 0.44 NA 8 0.35 FALSE 0.295 0.910 0.118
8 3 f2 0.35 NA 10 0.29 FALSE 0.293 0.912 0.132
11 4 f2 0.29 NA 13 0.25 FALSE 0.289 0.914 0.149
14 5 f2 0.25 NA 15 0.23 FALSE 0.290 0.914 0.150
17 6 f2 0.23 NA 16 0.23 TRUE 0.289 0.914 0.147
iter GP_func l c m l_hat l_hat > l rmse R2 elpd
3 1 f3 0.50 NA 7 1.59 TRUE 0.306 0.904 0.079
6 2 f3 1.59 NA 5 1.70 TRUE 0.295 0.910 0.118
9 3 f3 1.70 NA 5 1.57 FALSE 0.293 0.912 0.132
12 4 f3 1.57 NA 5 1.64 TRUE 0.289 0.914 0.149
15 5 f3 1.64 NA 5 1.78 TRUE 0.290 0.914 0.150
18 6 f3 1.78 NA 5 1.65 FALSE 0.289 0.914 0.147

Plots of the mean posterior functions from the last iteration

Extracting estimated function components \(f_1\), \(f_2\), \(f_3\) and \(f_4\)

f <- summary(fit[[i]], pars = c("f"), probs = c(0.025, 0.5, 0.975))$summary
intercept <- summary(fit[[i]], pars = c("intercept"), probs = c(0.025, 0.5, 0.975))$summary
f1 <- summary(fit[[i]], pars = c("f1"), probs = c(0.025, 0.5, 0.975))$summary
f2 <- summary(fit[[i]], pars = c("f2"), probs = c(0.025, 0.5, 0.975))$summary
f3 <- summary(fit[[i]], pars = c("f3"), probs = c(0.025, 0.5, 0.975))$summary
f4 <- summary(fit[[i]], pars = c("f4"), probs = c(0.025, 0.5, 0.975))$summary

Plot of only one year, the year 1972

Plot of all the years

Plot of only the first month

Plot of the first four years

LS0tDQp0aXRsZTogJ0JpcnRoZGF5IGRhdGEgY2FzZSBzdHVkeTogRGlhZ25vc2lzIG9mIHRoZSBIU0dQIGFwcHJveGltYXRpb24nDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy5EYXRlKCkpYC4iDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdGhlbWU6IHJlYWRhYmxlDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IA0KICAgICAgY29sbGFwc2VkOiB0cnVlDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgZGZfcHJpbnQ6IGthYmxlDQotLS0NCg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCmJvZHksIHRkeyBmb250LXNpemU6IDE2cHg7IH0NCmNvZGUucnsgZm9udC1zaXplOiAxMnB4OyB9DQpwcmV7IGZvbnQtc2l6ZTogMTJweCB9DQo8L3N0eWxlPg0KDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGNvbW1lbnQ9IiIpDQpgYGANCg0KIyMgTG9hZCBwYWNrYWdlcw0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBldmFsPVRSVUV9DQpsaWJyYXJ5KHJzdGFuKQ0KbGlicmFyeShjbWRzdGFucikNCm9wdGlvbnMobWMuY29yZXMgPSBwYXJhbGxlbDo6ZGV0ZWN0Q29yZXMoKSkNCnJzdGFuX29wdGlvbnMoYXV0b193cml0ZSA9IEZBTFNFKQ0KbGlicmFyeShwb3N0ZXJpb3IpDQpsaWJyYXJ5KGJheWVzcGxvdCkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkobG9vKQ0KbGlicmFyeShsYXRleDJleHApDQojIGxpYnJhcnkocmVzaGFwZTIpDQojIGxpYnJhcnkocGx5cikNCmBgYA0KDQojIyBEYXRhDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpkYXRhIDwtIHJlYWQuY3N2KGZpbGU9ImJpcnRoc191c2FfMTk2OS5jc3YiKQ0Kc3RyKGRhdGEpDQpgYGANCg0KYGBge3IgbWVzc2FnZT1UUlVFLCB3YXJuPVRSVUUsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTgsIGVjaG89RkFMU0V9DQpwYXIobWFpPWMoMS4wMiwxLjIsMC4zLDAuNDIpKQ0KDQppbmQgPC0gZGF0YSRpZA0KYmlydGhzIDwtIGRhdGEkYmlydGhzDQpsYWJlbHNfYXQgPSBhZ2dyZWdhdGUoZGF0YSwgYnk9bGlzdChkYXRhJHllYXIpLCBGVU49bWluKSRpZA0KDQpwbG90KGluZCwgYmlydGhzW2luZF0sIHR5cGU9InAiLCBwY2g9MjAsIGJnPWdyZXkoMC40KSwgY2V4PTAuNiwgY29sPWdyZXkoMC41KSwgeGxhYj0iIiwgeWxhYj0iIiwgbHdkPTEsIG1ncD1jKDMuNSwgMSwgMCksIGZyYW1lLnBsb3Q9VFJVRSwgeWF4cz0iciIsIGNleC5heGlzPTEuMiwgY2V4LmxhYj0xLjIsIGxhcz0xLCB4YXh0PSJuIiwgeWF4dD0ibiIsIGZnPWdyZXkoMC41KSwgZmFtaWx5PSJzZXJpZiIpDQpheGlzKDEsIGF0ID0gbGFiZWxzX2F0LCBjKCIxOTY5IiwiMTk3MCIsIjE5NzEiLCIxOTcyIiwiMTk3MyIsIjE5NzQiLCIxOTc1IiwiMTk3NiIsIjE5NzciLCIxOTc4IiwiMTk3OSIsIjE5ODAiLCIxOTgxIiwiMTk4MiIsIjE5ODMiLCIxOTg0IiwiMTk4NSIsIjE5ODYiLCIxOTg3IiwiMTk4OCIpLCBsdHk9MSwgbWdwPWMoMywgMC43LCAwKSwgbGFzPTEsIGNleC5heGlzPTEuMiwgZm9udD0xLCBjb2w9Z3JleSgwLjUpLCBjb2wudGlja3M9Z3JleSgwLjMpLCBmYW1pbHk9IiIpDQpheGlzKDIsIGx0eT0xLCBtZ3A9YygzLCAwLjcsIDApLCBsYXM9MSwgY2V4LmF4aXM9MS4yLCBmb250PTUsIGNvbD1ncmV5KDAuNSksIGNvbC50aWNrcz1ncmV5KDAuMykpDQp0aXRsZSh4bGFiPSJZZWFyIiwgbWdwPWMoMi4yLCAxLCAwKSwgY2V4LmxhYj0xLjIsIGxhcz0xKQ0KdGl0bGUoeWxhYj0iQmlydGhzIiwgbWdwPWMoMy43LCAwLjcsIDApLCBjZXgubGFiPTEuMiwgbGFzPTEpDQpsZWdlbmQoInRvcGxlZnQiLGluc2V0PWMoMC4yMiwwLjAyKSxsZWdlbmQ9YygiT2JzZXJ2YXRpb25zIiksIGNvbD1ncmV5KDAuNCksIGx0eT1OQSwgcGNoPTIwLCBsd2Q9MSwgY2V4PTEsIHhwZD1UUlVFLCBidHk9Im4iLCB4LmludGVyc3A9MC4xLCB0ZXh0LmZvbnQ9MSkNCmBgYA0KDQpJbnB1dCB2ZWN0b3INCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCnggPC0gc2NhbGUoZGF0YSRpZFtdLCBjZW50ZXI9VFJVRSwgc2NhbGU9VFJVRSkNCmBgYA0KDQpPdXRwdXQgdmVjdG9yDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQp5IDwtIHNjYWxlKGRhdGEkYmlydGhzW10sIGNlbnRlcj1UUlVFLCBzY2FsZT1UUlVFKQ0KYGBgDQoNClN0YW5kYXJkIGRldmlhdGlvbiBhbmQgbWVhbiBvZiB0aGUgb3V0cHV0DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpzdGRfeSA8LSBhdHRyKHksInNjYWxlZDpzY2FsZSIpDQptX3kgPC0gYXR0cih5LCJzY2FsZWQ6Y2VudGVyIikNCmBgYA0KDQpTdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIGlucHV0DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpzdGRfeCA8LSBhdHRyKHgsInNjYWxlZDpzY2FsZSIpDQpzdGRfeA0KYGBgDQoNClllYXIgYW5kIHdlZWsgcGVyaW9kcw0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KcGVyaW9kX3llYXIgPC0gMzY1LjI1L3N0ZF94DQpwZXJpb2Rfd2VlayA8LSA3L3N0ZF94DQpgYGANCg0KYERheSBvZiB0aGUgeWVhcjJgIGlzIGEgdmFyaWFibGUgdGhhdCBpbmRpY2F0ZXMgdGhlIGNvcnJlc3BvbmRlbmNlIGJldHdlZW4gYWxsIHRoZSBkYXlzIHdpdGggdGhlIGRheXMgb2YgYSBsZWFwLXllYXINCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmRheV9vZl95ZWFyMiA8LSBkYXRhJGRheV9vZl95ZWFyMg0KYGBgDQoNCkhhbGYgcmFuZ2Ugb2YgdGhlIGlucHV0IGRvbWFpbg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KUyA8LSAobWF4KHgpIC0gbWluKHgpKS8yDQpTDQpgYGANCg0KIyMgUmVsYXRpb25zaGlwcyBhbW9uZyAkbSQsICRsJCBhbmQgJGMkDQoNCjEuIFJlbGF0aW9uc2hpcCBhbW9uZyB0aGUgbnVtYmVyIG9mIGJhc2lzIGZ1bmN0aW9ucyAkbSQsIHRoZSBsZW5ndGhzY2FsZSAkbCQgYW5kIHRoZSBib3VuZGFyeSBmYWN0b3IgJGMkIGZvciBhICoqc3F1YXJlZCBleHBvbmVudGlhbCBrZXJuZWwqKjoNCg0KJCQgbT0gMS43MyBcLCBcZnJhY3tjfXtcbGVmdChcZnJhY3tsfXtTfVxyaWdodCleezEuMDV9fSwgXDtcO1w7IHtcc21hbGxcdGV4dHtvciBlcXVpdmFsZW50bHksfX0gXDtcO1w7IFxmcmFje2x9e1N9PSAxLjY4IFwsIFxmcmFje2NeezAuOTV9fXttXnswLjk1fX0kJA0KDQp3aXRoICRjIFwsIFxnZXEgXCwgMC45NyArIDEuNDUgXCwgXGZyYWN7bH17U30kLCBhbmQgJFMkIGJlaW5nIHRoZSBoYWxmIHJhbmdlIG9mIHRoZSBpbnB1dCBkb21haW4uDQoNCjIuIFJlbGF0aW9uc2hpcCBiZXR3ZWVuICRtJCBhbmQgJGwkIGZvciBhICoqc3F1YXJlZCBleHBvbmVudGlhbCBwZXJpb2RpYyBrZXJuZWwqKjoNCg0KJCRtPSAzLjMxIFwsIFxmcmFjezF9e2xeezEuMDV9fSwgXDtcO1w7IHtcc21hbGxcdGV4dHtvciBlcXVpdmFsZW50bHksfX0gXDtcO1w7IGw9IDMuMTIgXCwgXGZyYWN7MX17bV57MC45NX19JCQNCg0KIyMgTW9kZWwgDQoNCkxldCAkeV90JCBkZW5vdGUgdGhlIG51bWJlciBvZiBiaXJ0aHMgb24gdGhlICR0JCd0aCBkYXksIA0KDQpcYmVnaW57YWxpZ24qfQ0KJnlfe3R9IFxzaW0gXHRleHR7Tm9ybWFsfShcbXUodCksXHNpZ21hXjIpLCBcXA0KJlxtdSh0KSA9IGZfMSh0KSArIGZfMih0KSArIGZfMyh0KSArIGZfNCh0KQ0KXGVuZHthbGlnbip9DQoNClRoZSBjb21wb25lbnQgJGZfMSh0KSQgcmVwcmVzZW50cyB0aGUgbG9uZy10ZXJtIHRyZW5kcyBtb2RlbGVkIGJ5IGEgR1Agd2l0aCBzcXVhcmVkIGV4cG9uZW50aWFsIGNvdmFyaWFuY2UgZnVuY3Rpb24sDQoNClxiZWdpbntlcXVhdGlvbip9DQpmXzEodCkgXHNpbSBcdGV4dHtHUH0oMCxrXzEpLCBcaHNwYWNlezVtbX0ga18xKHQsdCcpID0gXGFscGhhXzEgXGV4cFwhXCFcbGVmdChcIS1cZnJhY3sxfXsyfSBcZnJhY3sodC10JyleMn17XGVsbF8xXjJ9XHJpZ2h0KSANClxlbmR7ZXF1YXRpb24qfQ0KDQpUaGUgY29tcG9uZW50ICRmXzIodCkkIHJlcHJlc2VudHMgdGhlIHllYXJseSBzbW9vdGggc2Vhc29uYWwgcGF0dGVybiwgdXNpbmcgYSBwZXJpb2RpYyBzcXVhcmVkIGV4cG9uZW50aWFsIGNvdmFyaWFuY2UgZnVuY3Rpb24gKHdpdGggcGVyaW9kIDM2NS4yNSB0byBtYXRjaCB0aGUgYXZlcmFnZSBsZW5ndGggb2YgdGhlIHllYXIpIGluIGEgR1AgbW9kZWwsDQoNClxiZWdpbnthbGlnbip9DQomZl8yKHQpIFxzaW0gXHRleHR7R1B9KDAsa18yKSwgXFwNCiZrXzIodCx0JykgPSBcYWxwaGFfMiBcZXhwXCFcIVxsZWZ0KFwhLVxmcmFjezJcLFxzaW5ee1whMn1cIShccGkodC10JykvMzY1LjI1fXtcZWxsXzJeMn1ccmlnaHQpDQpcZW5ke2FsaWduKn0NCg0KVGhlIGNvbXBvbmVudCAkZl8zKHQpJCByZXByZXNlbnRzIHRoZSB3ZWVrbHkgc21vb3RoIHBhdHRlcm4gdXNpbmcgYSBwZXJpb2RpYyBzcXVhcmVkIGV4cG9uZW50aWFsIGNvdmFyaWFuY2UgZnVuY3Rpb24gKHdpdGggcGVyaW9kIDcgb2YgbGVuZ3RoIG9mIHRoZSB3ZWVrKSBpbiBhIEdQIG1vZGVsLA0KDQpcYmVnaW57YWxpZ24qfQ0KJmZfMyh0KSBcc2ltIFx0ZXh0e0dQfSgwLGtfMyksIFxcDQoma18zKHQsdCcpID0gXGFscGhhXzMgXGV4cFwhXCFcbGVmdChcIS1cZnJhY3syXCxcc2luXntcITJ9XCEoXHBpKHQtdCcpLzd9e1xlbGxfM14yfVxyaWdodCkNClxlbmR7YWxpZ24qfQ0KDQpUaGUgY29tcG9uZW50ICRmXzQodCkkIHJlcHJlc2VudHMgdGhlIHNwZWNpYWwgZGF5cyBlZmZlY3RzIG1vZGVsZWQgYXMgdC1zdHVkZW50IGRpc3RyaWJ1dGlvbjoNCg0KXGJlZ2lue2FsaWduKn0NCiZmXzQodCkgXHNpbSBcdGV4dHt0LXN0dWRlbnR9KDAsXGFscGhhXzReMiksIFw7IHtcc21hbGxcdGV4dHt3aXRoIDEgZGVncmVlIG9mIGZyZWVkb219fSxcXA0KJlxhbHBoYV80IFxzaW0gXHRleHR7Tm9ybWFsfSgwLDAuMSkNClxlbmR7YWxpZ24qfQ0KDQoqKk1vZGVsIGluIFN0YW4gY29kZSoqDQoNCmBgYA0KLy9zYXZlZCBpbiAnc3RhbmNvZGVfZGVmLnN0YW4nDQpmdW5jdGlvbnMgew0KICB2ZWN0b3IgZGlhZ1NQRF9FUShyZWFsIGdwc2NhbGUsIHJlYWwgbHNjYWxlLCByZWFsIEwsIGludCBNKSB7DQogICAgcmV0dXJuIHNxcnQoKGdwc2NhbGVeMikgKiBzcXJ0KDIqcGkoKSkgKiBsc2NhbGUgKiBleHAoLTAuNSoobHNjYWxlKnBpKCkvMi9MKV4yICogbGluc3BhY2VkX3ZlY3RvcihNLCAxLCBNKV4yKSk7DQogIH0NCiAgdmVjdG9yIGRpYWdTUERfcGVyaW9kaWMocmVhbCBncHNjYWxlLCByZWFsIGxzY2FsZSwgaW50IE0pIHsNCiAgICByZWFsIGEgPSAxL2xzY2FsZV4yOw0KICAgIGludCBvbmVfdG9fTVtNXTsNCiAgICBmb3IgKG0gaW4gMTpNKSBvbmVfdG9fTVttXSA9IG07DQogICAgdmVjdG9yW01dIHEgPSBzcXJ0KGdwc2NhbGVeMiAqIDIgLyBleHAoYSkgKiB0b192ZWN0b3IobW9kaWZpZWRfYmVzc2VsX2ZpcnN0X2tpbmQob25lX3RvX00sIGEpKSk7DQogICAgcmV0dXJuIGFwcGVuZF9yb3cocSxxKTsNCiAgfQ0KICBtYXRyaXggUEhJX0VRKGludCBOLCBpbnQgTSwgcmVhbCBMLCB2ZWN0b3IgeCkgew0KICAgICBtYXRyaXhbTixNXSBQSEkgPSBzaW4oZGlhZ19wb3N0X211bHRpcGx5KHJlcF9tYXRyaXgocGkoKS8oMipMKSAqICh4K0wpLCBNKSwgbGluc3BhY2VkX3ZlY3RvcihNLCAxLCBNKSkpL3NxcnQoTCk7DQogICAgIGZvciAobSBpbiAxOk0pDQogICAgICAgUEhJWyxtXSA9IFBISVssbV0gLSBtZWFuKFBISVssbV0pOw0KICAgICByZXR1cm4gUEhJOw0KICB9DQogIG1hdHJpeCBQSElfcGVyaW9kaWMoaW50IE4sIGludCBNLCByZWFsIHcwLCB2ZWN0b3IgeCkgew0KICAgIG1hdHJpeFtOLE1dIG13MHggPSBkaWFnX3Bvc3RfbXVsdGlwbHkocmVwX21hdHJpeCh3MCp4LCBNKSwgbGluc3BhY2VkX3ZlY3RvcihNLCAxLCBNKSk7DQogICAgbWF0cml4W04sTV0gUEhJID0gYXBwZW5kX2NvbChjb3MobXcweCksIHNpbihtdzB4KSk7DQogICAgZm9yIChtIGluIDE6TSkNCiAgICAgIFBISVssbV0gPSBQSElbLG1dIC0gbWVhbihQSElbLG1dKTsNCiAgICByZXR1cm4gUEhJOw0KICB9DQp9DQpkYXRhIHsNCiAgICByZWFsIGNfZjE7ICAgICAgICAgICAgICAgICAgLy9ib3VuZGFyeSB2YWx1ZSBmb3IgZnVuY3Rpb24gMQ0KICAgIGludDxsb3dlcj0xPiBNX2YxOyAgICAgICAgICAvL251bSBiYXNpcyBmdW5jdGlvbnMgZm9yIGZ1bmN0aW9uIDENCiAgICBpbnQ8bG93ZXI9LTE+IEpfZjI7ICAgICAgICAgLy9udW0gY29zaW5lIGFuZCBzaW51IGZ1bmN0aW9ucyBmb3IgZnVuY3Rpb24gMw0KICAgIGludDxsb3dlcj0tMT4gSl9mMzsgICAgICAgICAvL251bSBjb3NpbmUgYW5kIHNpbnUgZnVuY3Rpb25zIGZvciBmdW5jdGlvbiA0DQogICAgaW50PGxvd2VyPTE+IE47ICAgICAgICAgICAgIC8vbnVtIG9ic2VydmF0aW9ucw0KICAgIHZlY3RvcltOXSB4OyAgICAgICAgICAgICAgICAvL2lucHV0IHZlY3Rvcg0KICAgIHZlY3RvcltOXSB5OyAgICAgICAgICAgICAgICAvL3RhcmdldCB2ZWN0b3INCiAgICByZWFsIHBlcmlvZF95ZWFyOyAgICAgICAgICAgLy9wZXJpb2Qgb2YgdGhlIHllYXINCiAgICByZWFsIHBlcmlvZF93ZWVrOyAgICAgICAgICAgLy9wZXJpb2Qgb2YgdGhlIHdlZWsNCiAgICBpbnQgZGF5X29mX3llYXIyW05dOyAgICAgICAgLy9kYXkgb2YgdGhlIHllYXIgaW5zaWRlIGEgbGVhcC15ZWFyDQp9DQp0cmFuc2Zvcm1lZCBkYXRhIHsNCiAgICByZWFsIExfZjE9IGNfZjEqbWF4KGZhYnMoeCkpOw0KICAgIC8vQmFzaXMgZnVuY3Rpb25zIGZvciBmMSwgZjIgYW5kIGYzDQogICAgbWF0cml4W04sTV9mMV0gUEhJX2YxID0gUEhJX0VRKE4sIE1fZjEsIExfZjEsIHgpOw0KICAgIG1hdHJpeFtOLDIqSl9mMl0gUEhJX2YyID0gUEhJX3BlcmlvZGljKE4sIEpfZjIsIDIqcGkoKS9wZXJpb2RfeWVhciwgeCk7DQogICAgbWF0cml4W04sMipKX2YzXSBQSElfZjMgPSBQSElfcGVyaW9kaWMoTiwgSl9mMywgMipwaSgpL3BlcmlvZF93ZWVrLCB4KTsNCn0NCnBhcmFtZXRlcnMgew0KICAgIHZlY3RvcltOXSBmOw0KICAgIHJlYWwgaW50ZXJjZXB0Ow0KICAgIC8vdmFyaWFibGVzIGZvciB0aGUgYmFzaXMgZnVuY3Rpb24gbW9kZWxzDQogICAgdmVjdG9yW01fZjFdIGJldGFfZjE7DQogICAgdmVjdG9yWzIqSl9mMl0gYmV0YV9mMjsNCiAgICB2ZWN0b3JbMipKX2YzXSBiZXRhX2YzOw0KICAgIC8vaHlwZXJwYXJhbWV0ZXJzDQogICAgdmVjdG9yPGxvd2VyPTA+WzNdIGxzY2FsZTsNCiAgICB2ZWN0b3I8bG93ZXI9MD5bM10gZ3BzY2FsZTsNCiAgICByZWFsPGxvd2VyPTA+IG5vaXNlOw0KICAgIC8vDQogICAgLy90LXN0dWRlbnQgcHJpb3IgZm9yIHNwZWNpYWwgZGF5cyBlZmZlY3RzDQogICAgdmVjdG9yWzM2Nl0gZjQ7DQogICAgcmVhbDxsb3dlcj0wPiBzaWdtYV9mNDsNCn0NCnRyYW5zZm9ybWVkIHBhcmFtZXRlcnN7DQogICAgdmVjdG9yW05dIGYxOw0KICAgIHZlY3RvcltOXSBmMjsNCiAgICB2ZWN0b3JbTl0gZjM7DQogICAgew0KICAgIHZlY3RvcltNX2YxXSBkaWFnU1BEX2YxID0gZGlhZ1NQRF9FUShncHNjYWxlWzFdLCBsc2NhbGVbMV0sIExfZjEsIE1fZjEpOw0KICAgIHZlY3RvclsyKkpfZjJdIGRpYWdTUERfZjIgPSBkaWFnU1BEX3BlcmlvZGljKGdwc2NhbGVbMl0sIGxzY2FsZVsyXSwgSl9mMik7DQogICAgdmVjdG9yWzIqSl9mM10gZGlhZ1NQRF9mMyA9IGRpYWdTUERfcGVyaW9kaWMoZ3BzY2FsZVszXSwgbHNjYWxlWzNdLCBKX2YzKTsNCiAgICAvLw0KICAgIHZlY3RvcltNX2YxXSBTUERfYmV0YV9mMSA9IGRpYWdTUERfZjEgLiogYmV0YV9mMTsNCiAgICB2ZWN0b3JbMipKX2YyXSBTUERfYmV0YV9mMiA9IGRpYWdTUERfZjIgLiogYmV0YV9mMjsNCiAgICB2ZWN0b3JbMipKX2YzXSBTUERfYmV0YV9mMyA9IGRpYWdTUERfZjMgLiogYmV0YV9mMzsNCiAgICAvLw0KICAgIGYxID0gUEhJX2YxWyxdICogU1BEX2JldGFfZjE7DQogICAgZjIgPSBQSElfZjJbLF0gKiBTUERfYmV0YV9mMjsNCiAgICBmMyA9IFBISV9mM1ssXSAqIFNQRF9iZXRhX2YzOw0KICAgIH0NCn0NCm1vZGVsew0KICAgIGludGVyY2VwdCB+IG5vcm1hbCgwLDEpOw0KICAgIGJldGFfZjEgfiBub3JtYWwoMCwxKTsNCiAgICBiZXRhX2YyIH4gbm9ybWFsKDAsMSk7DQogICAgYmV0YV9mMyB+IG5vcm1hbCgwLDEpOw0KICAgIC8vDQogICAgbHNjYWxlIH4gbm9ybWFsKDAsMik7ICAgICAgICAgICAvL0dQIGxlbmd0aHNjYWxlcw0KICAgIGdwc2NhbGUgfiBub3JtYWwoMCwxMCk7ICAgICAgICAgLy9HUCBtYWduaXR1ZGVzDQogICAgbm9pc2UgfiBub3JtYWwoMCwxKTsgICAgICAgICAgICAvL21vZGVsIG5vaXNlDQogICAgLy8NCiAgICAvL3Qtc3R1ZGVudCBwcmlvciBmb3Igc3BlY2lhbCBkYXlzIGVmZmVjdHMNCiAgICBmNCB+IHN0dWRlbnRfdCgxLCAwLCBzaWdtYV9mNCk7DQogICAgc2lnbWFfZjQgfiBub3JtYWwoMCwgMC4xKTsNCiAgICAvLw0KICAgIGY9IGludGVyY2VwdCArIGYxICsgZjIgKyBmMyArIGY0W2RheV9vZl95ZWFyMl07DQogICAgdGFyZ2V0ICs9IG5vcm1hbF9scGRmKHkgfCBmLCBub2lzZSk7DQp9DQpnZW5lcmF0ZWQgcXVhbnRpdGllc3sNCiAgdmVjdG9yW05dIHlfcmVwOw0KICB2ZWN0b3JbTl0gbG9nX2xpazsNCiAgZm9yKG4gaW4gMTpOKXsNCiAgICB5X3JlcFtuXSA9IG5vcm1hbF9ybmcoZltuXSwgbm9pc2UpOw0KICAgIGxvZ19saWtbbl0gPSBub3JtYWxfbHBkZih5W25dIHwgZltuXSwgbm9pc2UpOw0KICB9DQp9DQpgYGANCg0KIyMgVXNlci1ndWlkZSBmb3IgZGlhZ25vc2lzDQoNCioqQXNzdW1wdGlvbiBvZiB0aGUgZGlhZ25vc2lzIHRvb2w6KioNCg0KLSBVbmRlciBpbmFjY3VyYXRlIEhTR1AgYXBwcm94aW1hdGlvbiwgdGhlIGVzdGltYXRlZCBsZW5ndGhzY2FsZSAkXGhhdHtsfSQgaXMgKGFsd2F5cykgc21hbGxlciB0aGFuIHRoZSB0cnVlIGxlbmd0aHNjYWxlICRsJC4NCg0KKipVc2VyLWd1aWRlIHdpdGggdGhlIHN0ZXBzIHRvIHBlcmZvcm0gZGlhZ25vc2lzOioqDQoNCjAuIE1ha2UgYSBmaXJzdCBndWVzcyBvZiB0aGUgbGVuZ3Roc2NhbGUgJGxeMSQgb2YgdGhlIGZ1bmN0aW9uIHRvIGJlIGxlYXJuZWQuDQoNCipJdGVyYXRpb24gMSoNCg0KMS4gT2J0YWluIHRoZSBtaW5pbXVtIHZhbGlkIGJvdW5kYXJ5IGZhY3RvciAkY14xJCBkZXRlcm1pbmVkIGJ5IHRoZSBmaXJzdCBndWVzcyAkbF4xJCwgYnkgdXNpbmcgdGhlIGZ1bmN0aW9uYWwgcmVsYXRpb25zaGlwICRcLCBjXjEgXCwgXGdlcSBcLCAwLjk3ICsgMS40NSBcLCBcZnJhY3tsXjF9e1N9JCwgd2hlcmUgJFMkIHJlcHJlc2VudHMgdGhlIGhhbGYgcmFuZ2Ugb2YgdGhlIGlucHV0IGRvbWFpbi4NCg0KMi4gT2J0YWluIHRoZSBtaW1pbXVtIHZhbGlkIG51bWJlciBvZiBiYXNpcyBmdW5jdGlvbnMgJG1eMSQgZGV0ZXJtaW5lZCBieSAkbF4xJCBhbmQgJGNeMSQsIGJ5IHVzaW5nIHRoZSBmdW5jdGlvbmFsIHJlbGF0aW9uc2hpcCAkXCwgbV4xPSAxLjczIFwsIFxmcmFje2NeMX17XGxlZnQoXGZyYWN7bF4xfXtTfVxyaWdodCleezEuMDV9fSQuIE5vdGljZSB0aGF0ICRsXjEkIGNhbiBhbHNvIGJlIHJlYWQgYXMgdGhlIG1pbmltdW0gbGVuZ3Roc2NhbGUgdGhhdCBjYW4gYmUgYWNjdXJhdGVseSBmaXR0ZWQgZGV0ZXJtaW5lZCBieSAkbV4xJCBhbmQgJGNeMSQgJFxsZWZ0KFxmcmFje2xeMX17U309IDEuNjggXCwgXGZyYWN7KGNeMSleezAuOTV9fXsobV4xKV57MC45NX19XHJpZ2h0KSQuDQoNCjMuIEZpdCB0aGUgSFNHUCBtb2RlbCBhbmQgYXNzZXNzIHJlc2lkdWFsczogY2hlY2sgYW55IHJlc2lkdWFsIHRyZW5kcywgY29tcHV0ZSBybXNlIChSb290IG1lYW4gc3F1YXJlIGVycm9yKSwgJFJeMiQgKENvZWZmaWNpZW50IG9mIHZhcmlhdGlvbikgYW5kIGVscGQgKEV4cGVjdGVkIGxvZyBwcmVkaWNpdHZlIGRlbnNpdHkpLg0KDQo0LiBDaGVjayB3aGV0aGVyIHRoZSBlc3RpbWF0ZWQgJFxoYXR7bF4xfSQgaXMgZXF1YWwgdG8gb3IgZ3JlYXRlciB0aGFuIHRoYXQgJGxeMSQgKHRoZSBtaW5pbXVtIGxlbmd0aHNjYWxlIHRoYXQgY2FuIGJlIGFjY3VyYXRlbHkgZml0dGVkIGRldGVybWluZWQgYnkgdGhlICRtXjEkIGFuZCAkY14xJCB1c2VkKS4NCg0KNS4gSWYgdGhlIHZlcmlmaWNhdGlvbiBpbiBzdGVwIDQgaXMgVFJVRSwgdGhlIEhTR1AgbW9kZWwgYXBwcm94aW1hdGlvbiBtdXN0IGJlIHN1ZmZpY2llbnRseSBhY2N1cmF0ZSwgYW5kIGRpYWdub3NpcyBlbmRzIGhlcmUuIE90aGVyd2lzZSwgY29udGludWUgd2l0aCB0aGUgbmV4dCBzdGVwIDYuDQoNCipJdGVyYXRpb24gMioNCg0KNi4gVXNlIHRoZSBlc3RpbWF0ZWQgbGVuZ3Roc2NhbGUgJFxoYXR7bF4xfSQgdG8gb2J0YWluIHRoZSBuZXcgJGNeMiQuDQoNCjcuIFJlcGVhdCBzdGVwcyAxLTUgYW5kIHVwZGF0ZSBwYXJhbWV0ZXJzLg0KDQpOb3RlOiBJbiBvcmRlciB0byBiZSBhIGJpdCBtb3JlIGNvbnNlcnZhdGl2ZSBhbmQgbWFrZSBhcyBsZXNzIGl0ZXJhdGlvbnMgYXMgcG9zc2libGUgdG8gZ2V0IGFuIGFjY3VyYXRlIGFwcHJveGltYXRpb24sIDUgb3IgMTAgYmFzaXMgZnVuY3Rpb25zIGNhbiBiZSBhZGRlZCB0byB0aGUgY29tcHV0ZWQgJG0kIGluIGVhY2ggaXRlcmF0aW9uLg0KDQojIyBGaXR0aW5nIGFuZCBkaWFnbm9zaXMNCg0KSW5pdGlhbGl6aW5nIHByb2dyYW1taW5nIG9iamVjdHM6DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpzdGFuZGF0YSA8LSBsaXN0KCkNCmZpdCA8LSBsaXN0KCkNCmxfZjEgPC0gdmVjdG9yKCkNCmNfZjEgPC0gdmVjdG9yKCkNCm1fZjEgPC0gdmVjdG9yKCkNCmxfZjIgPC0gdmVjdG9yKCkNCm1fZjIgPC0gdmVjdG9yKCkNCmxfZjMgPC0gdmVjdG9yKCkNCm1fZjMgPC0gdmVjdG9yKCkNCmxfZjFfaGF0IDwtIHZlY3RvcigpDQpsX2YyX2hhdCA8LSB2ZWN0b3IoKQ0KbF9mM19oYXQgPC0gdmVjdG9yKCkNCnJlcyA8LSBsaXN0KCkNCmRpYWdub3NpcyA8LSBsaXN0KCkNCnJtc2UgPC0gdmVjdG9yKCkNCmVSMiA8LSB2ZWN0b3IoKQ0KZWxwZCA8LSB2ZWN0b3IoKQ0KYGBgDQoNCiMjIyBJdGVyYXRpb24gMQ0KDQpJdGVyYXRpb24gaW5kZXgNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmkgPC0gMQ0KYGBgDQoNCiMjIyMgU2V0dGluZyAkbSQsICRsJCBhbmQgJGMkDQoNCioqU21vb3RoIHRyZW5kIGZ1bmN0aW9uICRmXzEkKioNCg0KMS4gTWFraW5nIHRoZSBmaXJzdCBndWVzcyB0aGF0IHRoZSBsZW5ndGhzY2FsZSAkbCQgbWlnaHQgY29ycmVzcG9uZCB0byBhcm91bmQgMyB5ZWFycyAoMyozNjU9MTA5NSBkYXlzKSBvZiB0aGUgaW5wdXQgZGltZW5zaW9uDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpsX2YxW2ldIDwtIHJvdW5kKDEwOTUgLyBzdGRfeCwgMikNCmxfZjFbaV0NCmBgYA0KDQoyLiBUaGUgYm91bmRhcnkgZmFjdG9yICRjJCBoYXMgdG8gZnVsZmlsbCAkYyBcLCBcZ2VxIFwsIDAuOTcgKyAxLjQ1IFwsIFxmcmFje2x9e1N9JA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KMC45NyArIDEuNDUqbF9mMVtpXS9TDQpgYGANCg0KVGhlbiwgJGMkIGlzIHNldCB0bw0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KY19mMVtpXSA8LSAxLjUNCmNfZjFbaV0NCmBgYA0KDQozLiBUaGUgbnVtYmVyIG9mIGJhc2lzIGZ1bmN0aW9ucyAkbSQgYXMgYSBmdW5jdGlvbiBvZiAkbCQ6ICAkXDsgbT0gMS43MyBcLCBcZnJhY3tjfXsobC9TKV57MS4wNX19JA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbV9mMVtpXSA8LSBjZWlsaW5nKDEuNzMgKiBjX2YxW2ldLyhsX2YxW2ldL1MpXjEuMDUpDQptX2YxW2ldDQpgYGANCg0KKipZZWFybHkgcGVyaW9kaWMgZWZmZWN0cyBmdW5jdGlvbiAkZl8yJCoqDQoNCjEuIE1ha2luZyB0aGUgZmlyc3QgZ3Vlc3MgdGhhdCB0aGUgbGVuZ3Roc2NhbGUgJGwkIG1pZ2h0IGNvcnJlc3BvbmRzIHRvIGhhbGYgb2YgdGhlIHBlcmlvZCBvZiAkZl8yJC4gU28gJGw9MC41JA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mMltpXSA8LSAwLjUNCmxfZjJbaV0NCmBgYA0KDQoyLiBOdW1iZXIgb2YgYmFzaXMgZnVuY3Rpb25zICRtJCBhcyBhIGZ1bmN0aW9uIG9mICRsJDogICRcOyBtPSAzLjMxIFwsIFxmcmFjezF9e2xeezEuMDV9fSQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCm1fZjJbaV0gPC0gIGNlaWxpbmcoMy4zMSAqIDEvbF9mMltpXV4xLjA1KQ0KbV9mMltpXQ0KYGBgDQoNCioqV2Vla2x5IHBlcmlvZGljIGVmZmVjdHMgZnVuY3Rpb24gJGZfMyQqKg0KDQoxLiBNYWtpbmcgdGhlIGZpcnN0IGd1ZXNzIHRoYXQgdGhlIGxlbmd0aHNjYWxlICRsJCBtaWdodCBjb3JyZXNwb25kcyB0byBoYWxmIG9mIHRoZSBwZXJpb2Qgb2YgJGZfMyQuIFNvICRsPTAuNSQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjNbaV0gPC0gMC41DQpsX2YzW2ldDQpgYGANCg0KMi4gTnVtYmVyIG9mIGJhc2lzIGZ1bmN0aW9ucyAkbSQgYXMgYSBmdW5jdGlvbiBvZiAkbCQ6ICAkXDsgbT0gMy4zMSBcLCBcZnJhY3sxfXtsXnsxLjA1fX0kDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQptX2YzW2ldIDwtIGNlaWxpbmcoMy4zMSAqIDEvbF9mM1tpXV4xLjA1KQ0KbV9mM1tpXQ0KYGBgDQoNCiMjIyMgRGF0YSB0byBTdGFuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpzdGFuZGF0YVtbaV1dIDwtIGxpc3QoTV9mMT0gbV9mMVtpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgY19mMT0gY19mMVtpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgSl9mMj0gbV9mMltpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgSl9mMz0gbV9mM1tpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgeD0geFssMV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgIHk9IHlbLDFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBOPSBsZW5ndGgoeCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgIHBlcmlvZF95ZWFyPSBwZXJpb2RfeWVhciwgDQogICAgICAgICAgICAgICAgICAgICAgICAgcGVyaW9kX3dlZWs9IHBlcmlvZF93ZWVrLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGRheV9vZl95ZWFyMj0gZGF5X29mX3llYXIyDQopDQpzdHIoc3RhbmRhdGFbW2ldXSkNCmBgYA0KDQojIyMjIE1vZGVsIGZpdHRpbmcNCg0KQ29tcGlsaW5nIHRoZSBtb2RlbA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPVRSVUUsIGV2YWw9RkFMU0V9DQojIGJpcnRoZGF5X21vZCA8LSBjbWRzdGFucjo6Y21kc3Rhbl9tb2RlbChzdGFuX2ZpbGUgPSAic3RhbmNvZGVfZGVmLnN0YW4iKQ0KYGBgDQoNCk1vZGVsIHNhbXBsaW5nDQoNCmBgYHtyIHdhcm49VFJVRSwgbWVzc2FnZT1GQUxTRSwgZXZhbD1UUlVFfQ0KbG9hZCgiZml0LnJEYXRhIikNCmBgYA0KDQpgYGB7ciB3YXJuPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIGV2YWw9RkFMU0V9DQojIGZpdFtbaV1dIDwtIGJpcnRoZGF5X21vZCRzYW1wbGUoZGF0YT0gc3RhbmRhdGFbW2ldXSwgaXRlcl93YXJtdXA9MjAwLCBpdGVyX3NhbXBsaW5nPTIwMCwgY2hhaW5zPTQsIHRoaW49NCwgaW5pdD0wLjUsIGFkYXB0X2RlbHRhPTAuOSwgc2F2ZV93YXJtdXA9RkFMU0UpDQojIGZpdFtbaV1dIDwtIHJlYWRfc3Rhbl9jc3YoZml0W1tpXV0kb3V0cHV0X2ZpbGVzKCkpDQoNCiMgc2F2ZShmaXQsIGZpbGU9ImZpdC5yRGF0YSIpDQpgYGANCg0KU3VtbWFyaWVzIG9mIHZhcmlhYmxlIGVzdGltYXRlcw0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBldmFsPVRSVUV9DQpwYXJhbSA9IGMoImludGVyY2VwdCIsImxzY2FsZVsxXSIsImxzY2FsZVsyXSIsImxzY2FsZVszXSIsImdwc2NhbGVbMV0iLCJncHNjYWxlWzJdIiwiZ3BzY2FsZVszXSIsIm5vaXNlIiwic2lnbWFfZjQiKQ0Kc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IHBhcmFtLCBwcm9icyA9IGMoMC4wMjUsIDAuNSwgMC45NzUpLCBkaWdpdHNfc3VtbWFyeSA9IDQpJHN1bW1hcnkNCmBgYA0KDQpTaW11bGF0aW9uIGNoYWlucyBmb3IgdGhlIHZhcmlhYmxlcyBhZnRlciB3YXJtdXANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTUsIGV2YWw9VFJVRX0NCnRyYWNlcGxvdChmaXRbW2ldXSwgcGFycyA9IHBhcmFtLCBpbmNsdWRlID0gVFJVRSwgdW5jb25zdHJhaW4gPSBGQUxTRSwgaW5jX3dhcm11cCA9IEZBTFNFLCB3aW5kb3cgPSBOVUxMLCBucm93ID0gTlVMTCwgbmNvbCA9IE5VTEwpDQpgYGANCg0KUGxvdCBvZiB0aGUgbWVhbiBwb3N0ZXJpb3IgZnVuY3Rpb24gJGZfMSQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTUsIGZpZy5hbGlnbj0nY2VudGVyJywgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KZiA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygiZiIpLCBwcm9icyA9IGMoMC4wMjUsIDAuNSwgMC45NzUpKSRzdW1tYXJ5DQppbnRlcmNlcHQgPC0gc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IGMoImludGVyY2VwdCIpLCBwcm9icyA9IGMoMC4wMjUsIDAuNSwgMC45NzUpKSRzdW1tYXJ5DQpmMSA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygiZjEiKSwgcHJvYnMgPSBjKDAuMDI1LCAwLjUsIDAuOTc1KSkkc3VtbWFyeQ0KZjIgPC0gc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IGMoImYyIiksIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSkpJHN1bW1hcnkNCmYzIDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJmMyIpLCBwcm9icyA9IGMoMC4wMjUsIDAuNSwgMC45NzUpKSRzdW1tYXJ5DQpmNCA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygiZjQiKSwgcHJvYnMgPSBjKDAuMDI1LCAwLjUsIDAuOTc1KSkkc3VtbWFyeQ0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTE1LCBmaWcuYWxpZ249J2NlbnRlcicsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCnBhcihtYWk9YygxLCAwLjgyLCAwLjEsIDAuNDIpKQ0KDQppbmQgPC0gZGF0YSRpZA0KbGFiZWxzX2F0ID0gYWdncmVnYXRlKGRhdGEsIGJ5PWxpc3QoZGF0YSR5ZWFyKSwgRlVOPW1pbikkaWQNCg0Kb2JzX3BsdCA8LSAoKHlbaW5kXS1pbnRlcmNlcHRbMV0tZjJbaW5kLDFdLWYzW2luZCwxXS1mNFtkYXRhJGRheV9vZl95ZWFyMiwxXVtpbmRdKSpzdGRfeSttX3kpL21feQ0KcGxvdChpbmQsIG9ic19wbHQsIHR5cGU9InAiLCBwY2g9MjAsIGJnPWdyZXkoMC40KSwgY2V4PTAuNiwgY29sPWdyZXkoMC41KSwgeGxhYj0iIiwgeWxhYj0iIiwgbHdkPTEsIHlsaW09YygwLjgsMS4yKSwgbWdwPWMoMy41LCAxLCAwKSwgZnJhbWUucGxvdD1UUlVFLCB5YXhzPSJyIiwgY2V4LmF4aXM9MS42LCBjZXgubGFiPTEuNiwgbGFzPTEsIHhheHQ9Im4iLCB5YXh0PSJuIiwgZmc9Z3JleSgwLjUpLCBmYW1pbHk9InNlcmlmIikNCg0KYXhpcygxLCBhdD1sYWJlbHNfYXQsIGMoIjE5NjkiLCIxOTcwIiwiMTk3MSIsIjE5NzIiLCIxOTczIiwiMTk3NCIsIjE5NzUiLCIxOTc2IiwiMTk3NyIsIjE5NzgiLCIxOTc5IiwiMTk4MCIsIjE5ODEiLCIxOTgyIiwiMTk4MyIsIjE5ODQiLCIxOTg1IiwiMTk4NiIsIjE5ODciLCIxOTg4IiksIHRpY2s9VFJVRSwgbHR5PTEsIG1ncD1jKDMsIDEsIDApLCBsYXM9MSwgY2V4LmF4aXM9MS42LCBmb250PTEsIGNvbD1ncmV5KDAuNSksIGNvbC50aWNrcz1ncmV5KDAuMyksIGZhbWlseT0iIikNCmF4aXMoMiwgYXQ9TlVMTCwgbGFiZWxzPVRSVUUsIHRpY2s9VFJVRSwgbHR5PTEsIG1ncD1jKDMsIDAuNywgMCksIGxhcz0xLCBjZXguYXhpcz0xLjYsIGZvbnQ9NSwgY29sPWdyZXkoMC41KSwgY29sLnRpY2tzPWdyZXkoMC4zKSkNCnRpdGxlKHhsYWI9IlllYXIiLCBtZ3A9YygzLCAxLCAwKSwgY2V4LmxhYj0xLjYsIGxhcz0xKQ0KdGl0bGUoeWxhYj0iUHJvcG9ydGlvbiBvZiBiaXJ0aHMgb3ZlciB0aGUgbWVhbiIsIG1ncD1jKDMsIDAuNywgMCksIGNleC5sYWI9MS42LCBsYXM9MSkNCg0KYWJsaW5lKGg9MSwgbHR5PTIpCQkJCQkJCQkJCQkJICAgICAgICAgICAgICAgICMgbWVhbg0KbGluZXMoaW5kLCAoZjFbaW5kLDFdKnN0ZF95K21feSkvbV95LCBjb2w9MiwgbHdkPTIpCQkJCSMgZjENCg0KbGVnZW5kKCJ0b3BsZWZ0IiwgaW5zZXQ9YygwLjIyLDAuMDIpLCBsZWdlbmQ9YyhUZVgoJ09ic2VydmF0aW9ucyAtIGludGVyY2VwdCAtICRmXzIkIC0gJGZfMyQgLSAkZl80JCcpLFRlWCgnJGZfMSQnKSksIGNvbD1jKGdyZXkoMC40KSwyLDMsImdyZXkiKSwgbHR5PWMoTkEsMSwxLDEpLCBwY2g9YygyMCxOQSxOQSxOQSksIGx3ZD1jKDEsMywzLDMpLCBjZXg9MS40LCB4cGQ9VFJVRSwgYnR5PSJuIiwgeS5pbnRlcnNwPTEsIHguaW50ZXJzcD0wLjgsIHRleHQuZm9udD0xLCBuY29sPTEsIHNlZy5sZW49MS41KQ0KYGBgDQoNClBsb3Qgb2YgdGhlIG1lYW4gcG9zdGVyaW9yIGZ1bmN0aW9uICRmXzIkDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTE1LCBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQpwYXIobWFpPWMoMSwgMC44MiwgMC4xLCAwLjQyKSkNCg0KZGF0YV95ZWFyIDwtIGRhdGFbZGF0YSR5ZWFyICVpbiUgc2VxKDE5NjksMTk4MSwxKSxdDQppbmQgPC0gZGF0YV95ZWFyJGlkDQpheGlzX2xhYmVsc19hdCA8LSBhZ2dyZWdhdGUoZGF0YV95ZWFyLCBieT1saXN0KGRhdGFfeWVhciR5ZWFyKSwgRlVOPW1pbikkaWQNCg0Kb2JzIDwtICgoeVtpbmRdLWludGVyY2VwdFsxXS1mMVtpbmQsMV0tZjNbaW5kLDFdLWY0W2RhdGEkZGF5X29mX3llYXIyLDFdW2luZF0pKnN0ZF95K21feSkvbV95DQpwbG90KGluZCwgb2JzLCB0eXBlPSJwIiwgbHR5PTEsIHBjaD0yMCwgY2V4PTAuNiwgY29sPWdyZXkoMC41KSwgeGxhYj0iIiwgeWxhYj0iUHJvcG9ydGlvbiBvZiBiaXJ0aHMgb3ZlciB0aGUgbWVhbiIsIGNleC5sYWI9MS41LCBjZXguYXhpcz0xLjYsIHhheHQ9Im4iLCB5bGltPWMoMC44NSwxLjE1KSkNCg0KYXhpcygxLCBhdD1heGlzX2xhYmVsc19hdCwgbGFiZWxzPWFzLmNoYXJhY3RlcihzZXEoMTk2OSwxOTgxLDEpKSwgdGljaz1UUlVFLCBjZXguYXhpcz0xLjYpDQoNCmxpbmVzKHJhbmdlKGluZCksIGMoMSwxKSwgbHR5PTIsIGx3ZD0xKQkJCQkJCSAgICAgICAgIyBtZWFuDQpsaW5lcyhpbmQsIChmMltpbmQsMV0qc3RkX3krbV95KS9tX3ksIGNvbD0zLCBsd2Q9MikJIAkJICAjIGYyDQoNCmFibGluZSh2PWF4aXNfbGFiZWxzX2F0LCBsdHk9MiwgY29sPWdyZXkoMC43KSkNCmxlZ2VuZCgidG9wbGVmdCIsIGluc2V0PWMoMC4wNSwwLjAwNSksIGxlZ2VuZD1jKFRlWCgnT2JzZXJ2YXRpb25zIC0gaW50ZXJjZXB0IC0gJGZfMSQgLSAkZl8zJCAtICRmXzQkJyksVGVYKCckZl8yJCcpKSwgY29sPWMoZ3JleSgwLjUpLDMpLCBsdHk9YyhOQSwxKSwgcGNoPWMoMjAsTkEpLCBsd2Q9YygzLDMpLCBjZXg9MS40LCB4cGQ9VFJVRSwgYnR5PSJuIiwgeS5pbnRlcnNwPTEsIHguaW50ZXJzcD0wLjgsIHRleHQuZm9udD0xLCBuY29sPTEsIHNlZy5sZW49MS4zKQ0KYGBgDQoNClBsb3Qgb2YgdGhlIG1lYW4gcG9zdGVyaW9yIGZ1bmN0aW9uICRmXzEgKyBmXzIkDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTE1LCBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQpwYXIobWFpPWMoMSwgMC44MiwgMC4xLCAwLjQyKSkNCg0KZGF0YV95ZWFyIDwtIGRhdGFbZGF0YSR5ZWFyICVpbiUgc2VxKDE5NjksMTk4MSwxKSxdDQppbmQgPC0gZGF0YV95ZWFyJGlkDQpheGlzX2xhYmVsc19hdCA8LSBhZ2dyZWdhdGUoZGF0YV95ZWFyLCBieT1saXN0KGRhdGFfeWVhciR5ZWFyKSwgRlVOPW1pbikkaWQNCg0Kb2JzIDwtICgoeVtpbmRdLWludGVyY2VwdFsxXS1mM1tpbmQsMV0tZjRbZGF0YSRkYXlfb2ZfeWVhcjIsMV1baW5kXSkqc3RkX3krbV95KS9tX3kNCnBsb3QoaW5kLCBvYnMsIHR5cGU9InAiLCBsdHk9MSwgcGNoPTIwLCBjZXg9MC42LCBjb2w9Z3JleSgwLjUpLCB4bGFiPSIiLCB5bGFiPSJQcm9wb3J0aW9uIG9mIGJpcnRocyBvdmVyIHRoZSBtZWFuIiwgY2V4LmxhYj0xLjUsIGNleC5heGlzPTEuNiwgeGF4dD0ibiIsIHlsaW09YygwLjgsMS4yKSkNCg0KYXhpcygxLCBhdD1heGlzX2xhYmVsc19hdCwgbGFiZWxzPWFzLmNoYXJhY3RlcihzZXEoMTk2OSwxOTgxLDEpKSwgdGljaz1UUlVFLCBjZXguYXhpcz0xLjYpDQoNCmxpbmVzKHJhbmdlKGluZCksIGMoMSwxKSwgbHR5PTIsIGx3ZD0xKQkJCQkJCSAgICAgICAgICAgICAgICAgICAgIyBtZWFuDQpsaW5lcyhpbmQsICgoZjFbaW5kLDFdK2YyW2luZCwxXSkqc3RkX3krbV95KS9tX3ksIGNvbD00LCBsd2Q9MikJIAkJICAjIGYxICsgZjINCg0KYWJsaW5lKHY9YXhpc19sYWJlbHNfYXQsIGx0eT0yLCBjb2w9Z3JleSgwLjcpKQ0KbGVnZW5kKCJ0b3BsZWZ0IiwgaW5zZXQ9YygwLjA1LDAuMDA1KSwgbGVnZW5kPWMoVGVYKCdPYnNlcnZhdGlvbnMgLSBpbnRlcmNlcHQgLSAkZl8zJCAtICRmXzQkJyksVGVYKCckZl8xICsgZl8yJCcpKSwgY29sPWMoZ3JleSgwLjUpLDQpLCBsdHk9YyhOQSwxKSwgcGNoPWMoMjAsTkEpLCBsd2Q9YygzLDMpLCBjZXg9MS40LCB4cGQ9VFJVRSwgYnR5PSJuIiwgeS5pbnRlcnNwPTEsIHguaW50ZXJzcD0wLjgsIHRleHQuZm9udD0xLCBuY29sPTEsIHNlZy5sZW49MS4zKQ0KYGBgDQoNClBsb3Qgb2YgdGhlIHJlc2lkdWFscw0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xNSwgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KcGFyKG1haT1jKDEsIDAuODIsIDAuMSwgMC40MikpDQoNCmRhdGFfeWVhciA8LSBkYXRhW2RhdGEkeWVhciAlaW4lIHNlcSgxOTY5LDE5ODEsMSksXQ0KaW5kIDwtIGRhdGFfeWVhciRpZA0KYXhpc19sYWJlbHNfYXQgPC0gYWdncmVnYXRlKGRhdGFfeWVhciwgYnk9bGlzdChkYXRhX3llYXIkeWVhciksIEZVTj1taW4pJGlkDQoNCm9icyA8LSAoKHlbaW5kXS1pbnRlcmNlcHRbMV0tZjFbaW5kLDFdLWYyW2luZCwxXS1mM1tpbmQsMV0tZjRbZGF0YSRkYXlfb2ZfeWVhcjIsMV1baW5kXSkqc3RkX3krbV95KS9tX3kNCnBsb3QoaW5kLCBvYnMsIHR5cGU9InAiLCBsdHk9MSwgcGNoPTIwLCBjZXg9MC42LCBjb2w9Z3JleSgwLjUpLCB4bGFiPSIiLCB5bGFiPSJQcm9wb3J0aW9uIG9mIGJpcnRocyBvdmVyIHRoZSBtZWFuIiwgY2V4LmxhYj0xLjUsIGNleC5heGlzPTEuNiwgeGF4dD0ibiIsIHlsaW09YygwLjgsMS4yKSkNCg0KYXhpcygxLCBhdD1heGlzX2xhYmVsc19hdCwgbGFiZWxzPWFzLmNoYXJhY3RlcihzZXEoMTk2OSwxOTgxLDEpKSwgdGljaz1UUlVFLCBjZXguYXhpcz0xLjYpDQoNCmxpbmVzKHJhbmdlKGluZCksIGMoMSwxKSwgbHR5PTIsIGx3ZD0xKQkJCQkJCSAgICAgICAgICAgICAgICAgICAgIyBtZWFuDQoNCmFibGluZSh2PWF4aXNfbGFiZWxzX2F0LCBsdHk9MiwgY29sPWdyZXkoMC43KSkNCmxlZ2VuZCgidG9wbGVmdCIsIGluc2V0PWMoMC4wNSwwLjAwNSksIGxlZ2VuZD1jKFRlWCgnT2JzZXJ2YXRpb25zIC0gaW50ZXJjZXB0IC0gJGZfMSQgLSAkZl8yJCAtICRmXzMkIC0gJGZfNCQnKSksIGNvbD1jKGdyZXkoMC41KSw0KSwgbHR5PWMoTkEsMSksIHBjaD1jKDIwLE5BKSwgbHdkPWMoMywzKSwgY2V4PTEuNCwgeHBkPVRSVUUsIGJ0eT0ibiIsIHkuaW50ZXJzcD0xLCB4LmludGVyc3A9MC44LCB0ZXh0LmZvbnQ9MSwgbmNvbD0xLCBzZWcubGVuPTEuMykNCmBgYA0KDQojIyMjIE1vZGVsIGV2YWx1YXRpb24NCg0KUmVzaWR1YWxzDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTQsIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpmIDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJmIikpJHN1bW1hcnlbLDFdDQpyZXNbW2ldXSA8LSBzdGFuZGF0YVtbaV1dJHkgLSBmDQoNCmdncGxvdChhcy5kYXRhLmZyYW1lKHJlc1tbaV1dKSwgYWVzKHJlc1tbaV1dKSkgICsNCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3IgPSAnd2hpdGUnKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KYGBgDQoNClJvb3QgbWVhbiBzcXVhcmVkIGVycm9yDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpybXNlW2ldIDwtIHNxcnQobWVhbihyZXNbW2ldXV4yKSkNCnJtc2VbaV0NCmBgYA0KDQpCYXllc2lhbiAkUl4yJCAoQ29lZmZpY2llbnQgb2YgZGV0ZXJtaW5hdGlvbikNCg0KYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCm5vaXNlIDwtIGFzLm1hdHJpeChmaXRbW2ldXSwgcGFycyA9IGMoIm5vaXNlIikpDQpzZF9mIDwtIGFwcGx5KGFzLm1hdHJpeChmaXRbW2ldXSwgcGFycyA9IGMoImYiKSksIDEsIHNkKQ0KUjIgPC0gc2RfZl4yLyhzZF9mXjIgKyBub2lzZV4yKQ0KDQpnZ3Bsb3QoYXMuZGF0YS5mcmFtZShSMiksIGFlcyhSMikpICArDQogIGdlb21faGlzdG9ncmFtKGNvbG9yID0gJ3doaXRlJykgKw0KICB0aGVtZV9jbGFzc2ljKCkNCmBgYA0KDQpNZWRpYW4gb2YgJFJeMiQNCg0KYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmVSMltpXSA8LSBtZWRpYW4oUjIpDQplUjJbaV0NCmBgYA0KDQpMb2cgcHJlZGljdGl2ZSBkZW5zaXR5IChscGQpDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTQsIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpscGQgPC0gc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IGMoImxvZ19saWsiKSkkc3VtbWFyeVssMV0NCg0KZ2dwbG90KGFzLmRhdGEuZnJhbWUobHBkKSwgYWVzKGxwZCkpICArDQogIGdlb21faGlzdG9ncmFtKGNvbG9yID0gJ3doaXRlJykgKw0KICB0aGVtZV9jbGFzc2ljKCkNCmBgYA0KDQpNZWRpYW4gb2YgbHBkDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTQsIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQplbHBkW2ldIDwtIG1lZGlhbihscGQpDQplbHBkW2ldDQpgYGANCg0KIyMjIyBEaWFnbm9zaXMNCg0KKipTbW9vdGggdHJlbmQgZnVuY3Rpb24gJGZfMSQqKg0KDQoxLiBFc3RpbWF0ZWQgbGVuZ3Roc2NhbGUgJFxoYXR7bH0kICANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjFfaGF0W2ldIDwtIHJvdW5kKHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSAibHNjYWxlWzFdIikkc3VtbWFyeVssMV0sIDIpDQpsX2YxX2hhdFtpXQ0KYGBgDQoNCjIuIENoZWNrIHdoZXRoZXIgJFxoYXR7bH0kIGlzIGVxdWFsIHRvIG9yIGdyZWF0ZXIgdGhhbiBgbF9mMWAgKHRoZSBtaW5pbXVtICRsJCB0aGF0IGNhbiBiZSBhY2N1cmF0ZWx5IGZpdHRlZCBkZXRlcm1pbmVkIGJ5IHRoZSAkbSQgdXNlZCkNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjFfaGF0W2ldID49IGxfZjFbaV0NCmBgYA0KDQoqKlllYXJseSBwZXJpb2RpYyBlZmZlY3RzIGZ1bmN0aW9uICRmXzIkKioNCg0KMS4gRXN0aW1hdGVkIGxlbmd0aHNjYWxlICRcaGF0e2x9JCAgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpsX2YyX2hhdFtpXSA8LSByb3VuZChzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gImxzY2FsZVsyXSIpJHN1bW1hcnlbLDFdLCAyKQ0KbF9mMl9oYXRbaV0NCmBgYA0KDQoyLiBDaGVjayB3aGV0aGVyICRcaGF0e2x9JCBpcyBlcXVhbCB0byBvciBncmVhdGVyIHRoYW4gYGxfZjJgICh0aGUgbWluaW11bSAkbCQgdGhhdCBjYW4gYmUgYWNjdXJhdGVseSBmaXR0ZWQgZGV0ZXJtaW5lZCBieSB0aGUgJG0kIHVzZWQpDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpsX2YyX2hhdFtpXSA+PSBsX2YyW2ldDQpgYGANCg0KKipXZWVrbHkgcGVyaW9kaWMgZWZmZWN0cyBmdW5jdGlvbiAkZl8zJCoqDQoNCjEuIEVzdGltYXRlZCBsZW5ndGhzY2FsZSAkXGhhdHtsfSQgIA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mM19oYXRbaV0gPC0gcm91bmQoc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9ICJsc2NhbGVbM10iKSRzdW1tYXJ5WywxXSwgMikNCmxfZjNfaGF0W2ldDQpgYGANCg0KMi4gQ2hlY2sgd2hldGhlciAkXGhhdHtsfSQgaXMgZXF1YWwgdG8gb3IgZ3JlYXRlciB0aGFuIGBsX2YzYCAodGhlIG1pbmltdW0gJGwkIHRoYXQgY2FuIGJlIGFjY3VyYXRlbHkgZml0dGVkIGRldGVybWluZWQgYnkgdGhlICRtJCB1c2VkKQ0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mM19oYXRbaV0gPj0gbF9mM1tpXQ0KYGBgDQoNCioqU3VtbWFyeSB0YWJsZSoqDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTUsIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGVjaG89RkFMU0V9DQpkaWFnbm9zaXNbW2ldXSA8LSBkYXRhLmZyYW1lKGl0ZXI9IHJlcChpLDMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHUF9mdW5jPSBjKCJmMSIsICJmMiIsICJmMyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsPSByb3VuZChjKGxfZjFbaV0sIGxfZjJbaV0sIGxfZjNbaV0pLDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjPSByb3VuZChjKGNfZjFbaV0sIE5BLCBOQSksIDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtPSBjKG1fZjFbaV0sIG1fZjJbaV0sIG1fZjNbaV0pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsX2hhdD0gcm91bmQoYyhsX2YxX2hhdFtpXSwgbF9mMl9oYXRbaV0sIGxfZjNfaGF0W2ldKSwgMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdsX2hhdCA+IGwnID0gYyhsX2YxX2hhdFtpXSA+PSBsX2YxW2ldLCBsX2YyX2hhdFtpXSA+PSBsX2YyW2ldLCBsX2YzX2hhdFtpXSA+PSBsX2YzW2ldKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnNtZSA9IHJvdW5kKHJlcChybXNlW2ldLDMpLCAzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUjIgPSByb3VuZChyZXAoZVIyW2ldLDMpLCAzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxwZCA9IHJvdW5kKHJlcChlbHBkW2ldLDMpLCAzKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApDQpuYW1lcyhkaWFnbm9zaXNbW2ldXSkgPC0gYygiaXRlciIsICJHUF9mdW5jIiwgImwiLCAiYyIsICJtIiwgImxfaGF0IiwgImxfaGF0ID4gbCIsICJybXNlIiwgIlIyIiwgImVscGQiKQ0KZGlhZ25vc2lzW1tpXV0NCmBgYA0KDQojIyMgSXRlcmF0aW9uIDINCg0KSXRlcmF0aW9uIGluZGV4DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQppIDwtIDINCmBgYA0KDQojIyMjIFNldHRpbmcgJG0kLCAkbCQgYW5kICRjJA0KDQoqKlNtb290aCB0cmVuZCBmdW5jdGlvbiAkZl8xJCoqDQoNCjEuIFVwZGF0aW5nICRsJCB3aXRoIGl0cyBlc3RpbWF0ZSAkXGhhdHtsfSQgaW4gdGhlIGZpcnN0IGl0ZXJhdGlvbg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mMVtpXSA8LSBsX2YxX2hhdFtpLTFdDQpsX2YxW2ldDQpgYGANCg0KMi4gVGhlIGJvdW5kYXJ5IGZhY3RvciAkYyQgaGFzIHRvIGZ1bGZpbGwgJGMgXCwgXGdlcSBcLCAwLjk3ICsgMS40NSBcLCBcZnJhY3tsfXtTfSQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCjAuOTcgKyAxLjQ1KmxfZjFbaV0vUw0KYGBgDQoNClRoZW4sICRjJCBpcyBzZXQgdG8NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmNfZjFbaV0gPC0gMS41DQpjX2YxW2ldDQpgYGANCg0KMy4gVGhlIG51bWJlciBvZiBiYXNpcyBmdW5jdGlvbnMgJG0kIGFzIGEgZnVuY3Rpb24gb2YgJGwkOiAgJFw7IG09IDEuNzMgXCwgXGZyYWN7Y317KGwvUyleezEuMDV9fSQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmlmKDEuNzMgKiBjX2YxW2ldLyhsX2YxW2ldL1MpXjEuMDUgPCA1KSBtX2YxW2ldIDwtIDUgZWxzZSBtX2YxW2ldIDwtIGNlaWxpbmcoMS43MyAqIGNfZjFbaV0vKGxfZjFbaV0vUyleMS4wNSkNCm1fZjFbaV0NCmBgYA0KDQoqKlllYXJseSBwZXJpb2RpYyBlZmZlY3RzIGZ1bmN0aW9uICRmXzIkKioNCg0KMS4gVXBkYXRpbmcgJGwkIHdpdGggaXRzIGVzdGltYXRlICRcaGF0e2x9JCBpbiB0aGUgZmlyc3QgaXRlcmF0aW9uDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpsX2YyW2ldIDwtIGxfZjJfaGF0W2ktMV0NCmxfZjJbaV0NCmBgYA0KDQoyLiBOdW1iZXIgb2YgYmFzaXMgZnVuY3Rpb25zICRtJCBhcyBhIGZ1bmN0aW9uIG9mICRsJDogICRcOyBtPSAzLjMxIFwsIFxmcmFjezF9e2xeezEuMDV9fSQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmlmKDMuMzEgKiAxL2xfZjJbaV1eMS4wNSA8IDUpIG1fZjJbaV0gPC0gNSBlbHNlIG1fZjJbaV0gPC0gY2VpbGluZyggMy4zMSAqIDEvbF9mMltpXV4xLjA1KQ0KbV9mMltpXQ0KYGBgDQoNCioqV2Vla2x5IHBlcmlvZGljIGVmZmVjdHMgZnVuY3Rpb24gJGZfMyQqKg0KDQoxLiBVcGRhdGluZyAkbCQgd2l0aCBpdHMgZXN0aW1hdGUgJFxoYXR7bH0kIGluIHRoZSBmaXJzdCBpdGVyYXRpb24NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjNbaV0gPC0gbF9mM19oYXRbaS0xXQ0KbF9mM1tpXQ0KYGBgDQoNCjIuIE51bWJlciBvZiBiYXNpcyBmdW5jdGlvbnMgJG0kIGFzIGEgZnVuY3Rpb24gb2YgJGwkOiAgJFw7IG09IDMuMzEgXCwgXGZyYWN7MX17bF57MS4wNX19JA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KaWYoMy4zMSAqIDEvbF9mM1tpXV4xLjA1IDwgNSkgbV9mM1tpXSA8LSA1IGVsc2UgbV9mM1tpXSA8LSBjZWlsaW5nKDMuMzEgKiAxL2xfZjNbaV1eMS4wNSkNCm1fZjNbaV0NCmBgYA0KDQojIyMjIERhdGEgdG8gU3Rhbg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0Kc3RhbmRhdGFbW2ldXSA8LSBsaXN0KE1fZjE9IG1fZjFbaV0sIA0KICAgICAgICAgICAgICAgICBjX2YxPSBjX2YxW2ldLCANCiAgICAgICAgICAgICAgICAgSl9mMj0gbV9mMltpXSwgDQogICAgICAgICAgICAgICAgIEpfZjM9IG1fZjNbaV0sIA0KICAgICAgICAgICAgICAgICB4PSB4WywxXSwgDQogICAgICAgICAgICAgICAgIHk9IHlbLDFdLCANCiAgICAgICAgICAgICAgICAgTj0gbGVuZ3RoKHgpLCANCiAgICAgICAgICAgICAgICAgcGVyaW9kX3llYXI9IHBlcmlvZF95ZWFyLCANCiAgICAgICAgICAgICAgICAgcGVyaW9kX3dlZWs9IHBlcmlvZF93ZWVrLA0KICAgICAgICAgICAgICAgICBkYXlfb2ZfeWVhcjI9IGRheV9vZl95ZWFyMg0KKQ0Kc3RyKHN0YW5kYXRhW1tpXV0pDQpgYGANCg0KIyMjIyBNb2RlbCBmaXR0aW5nDQoNCkNvbXBpbGluZyB0aGUgbW9kZWwNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1UUlVFLCBldmFsPUZBTFNFfQ0KIyBiaXJ0aGRheV9tb2QgPC0gY21kc3RhbnI6OmNtZHN0YW5fbW9kZWwoc3Rhbl9maWxlID0gInN0YW5jb2RlX2RlZi5zdGFuIikNCmBgYA0KDQpNb2RlbCBzYW1wbGluZyAodXNpbmcgYGNtZHN0YW5yYCBwYWNrYWdlKQ0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBldmFsPVRSVUV9DQojIGxvYWQoImZpdC5yRGF0YSIpDQpgYGANCg0KYGBge3Igd2Fybj1UUlVFLCBtZXNzYWdlPUZBTFNFLCBldmFsPUZBTFNFfQ0KIyBmaXRbW2ldXSA8LSBiaXJ0aGRheV9tb2Qkc2FtcGxlKGRhdGE9IHN0YW5kYXRhW1tpXV0sIGl0ZXJfd2FybXVwPTIwMCwgaXRlcl9zYW1wbGluZz0yMDAsIGNoYWlucz00LCB0aGluPTQsIGluaXQ9MC41LCBhZGFwdF9kZWx0YT0wLjksIHNhdmVfd2FybXVwPUZBTFNFKQ0KIyBmaXRbW2ldXSA8LSByc3Rhbjo6cmVhZF9zdGFuX2NzdihmaXRbW2ldXSRvdXRwdXRfZmlsZXMoKSkNCg0KIyBzYXZlKGZpdCwgZmlsZT0iZml0LnJEYXRhIikNCmBgYA0KDQpTdW1tYXJpZXMgb2YgdmFyaWFibGUgZXN0aW1hdGVzDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGV2YWw9VFJVRX0NCnBhcmFtID0gYygiaW50ZXJjZXB0IiwibHNjYWxlWzFdIiwibHNjYWxlWzJdIiwibHNjYWxlWzNdIiwiZ3BzY2FsZVsxXSIsImdwc2NhbGVbMl0iLCJncHNjYWxlWzNdIiwibm9pc2UiLCJzaWdtYV9mNCIpDQpzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gcGFyYW0sIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSksIGRpZ2l0c19zdW1tYXJ5ID0gNCkkc3VtbWFyeQ0KYGBgDQoNClNpbXVsYXRpb24gY2hhaW5zIGZvciB0aGUgdmFyaWFibGVzIGFmdGVyIHdhcm11cA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xNSwgZXZhbD1UUlVFfQ0KdHJhY2VwbG90KGZpdFtbaV1dLCBwYXJzID0gcGFyYW0sIGluY2x1ZGUgPSBUUlVFLCB1bmNvbnN0cmFpbiA9IEZBTFNFLCBpbmNfd2FybXVwID0gRkFMU0UsIHdpbmRvdyA9IE5VTEwsIG5yb3cgPSBOVUxMLCBuY29sID0gTlVMTCkNCmBgYA0KDQpQbG90IG9mIHRoZSBtZWFuIHBvc3RlcmlvciBmdW5jdGlvbiAkZl8xJA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xNSwgZmlnLmFsaWduPSdjZW50ZXInLCBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQpmIDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJmIiksIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSkpJHN1bW1hcnkNCmludGVyY2VwdCA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygiaW50ZXJjZXB0IiksIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSkpJHN1bW1hcnkNCmYxIDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJmMSIpLCBwcm9icyA9IGMoMC4wMjUsIDAuNSwgMC45NzUpKSRzdW1tYXJ5DQpmMiA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygiZjIiKSwgcHJvYnMgPSBjKDAuMDI1LCAwLjUsIDAuOTc1KSkkc3VtbWFyeQ0KZjMgPC0gc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IGMoImYzIiksIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSkpJHN1bW1hcnkNCmY0IDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJmNCIpLCBwcm9icyA9IGMoMC4wMjUsIDAuNSwgMC45NzUpKSRzdW1tYXJ5DQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTUsIGZpZy5hbGlnbj0nY2VudGVyJywgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KcGFyKG1haT1jKDEsIDAuODIsIDAuMSwgMC40MikpDQoNCmluZCA8LSBkYXRhJGlkDQpsYWJlbHNfYXQgPSBhZ2dyZWdhdGUoZGF0YSwgYnk9bGlzdChkYXRhJHllYXIpLCBGVU49bWluKSRpZA0KDQpvYnNfcGx0IDwtICgoeVtpbmRdLWludGVyY2VwdFsxXS1mMltpbmQsMV0tZjNbaW5kLDFdLWY0W2RhdGEkZGF5X29mX3llYXIyLDFdW2luZF0pKnN0ZF95K21feSkvbV95DQpwbG90KGluZCwgb2JzX3BsdCwgdHlwZT0icCIsIHBjaD0yMCwgYmc9Z3JleSgwLjQpLCBjZXg9MC42LCBjb2w9Z3JleSgwLjUpLCB4bGFiPSIiLCB5bGFiPSIiLCBsd2Q9MSwgeWxpbT1jKDAuOCwxLjIpLCBtZ3A9YygzLjUsIDEsIDApLCBmcmFtZS5wbG90PVRSVUUsIHlheHM9InIiLCBjZXguYXhpcz0xLjYsIGNleC5sYWI9MS42LCBsYXM9MSwgeGF4dD0ibiIsIHlheHQ9Im4iLCBmZz1ncmV5KDAuNSksIGZhbWlseT0ic2VyaWYiKQ0KDQpheGlzKDEsIGF0PWxhYmVsc19hdCwgYygiMTk2OSIsIjE5NzAiLCIxOTcxIiwiMTk3MiIsIjE5NzMiLCIxOTc0IiwiMTk3NSIsIjE5NzYiLCIxOTc3IiwiMTk3OCIsIjE5NzkiLCIxOTgwIiwiMTk4MSIsIjE5ODIiLCIxOTgzIiwiMTk4NCIsIjE5ODUiLCIxOTg2IiwiMTk4NyIsIjE5ODgiKSwgdGljaz1UUlVFLCBsdHk9MSwgbWdwPWMoMywgMSwgMCksIGxhcz0xLCBjZXguYXhpcz0xLjYsIGZvbnQ9MSwgY29sPWdyZXkoMC41KSwgY29sLnRpY2tzPWdyZXkoMC4zKSwgZmFtaWx5PSIiKQ0KYXhpcygyLCBhdD1OVUxMLCBsYWJlbHM9VFJVRSwgdGljaz1UUlVFLCBsdHk9MSwgbWdwPWMoMywgMC43LCAwKSwgbGFzPTEsIGNleC5heGlzPTEuNiwgZm9udD01LCBjb2w9Z3JleSgwLjUpLCBjb2wudGlja3M9Z3JleSgwLjMpKQ0KdGl0bGUoeGxhYj0iWWVhciIsIG1ncD1jKDMsIDEsIDApLCBjZXgubGFiPTEuNiwgbGFzPTEpDQp0aXRsZSh5bGFiPSJQcm9wb3J0aW9uIG9mIGJpcnRocyBvdmVyIHRoZSBtZWFuIiwgbWdwPWMoMywgMC43LCAwKSwgY2V4LmxhYj0xLjYsIGxhcz0xKQ0KDQphYmxpbmUoaD0xLCBsdHk9MikJCQkJCQkJCQkJCQkgICAgICAgICAgICAgICAgIyBtZWFuDQpsaW5lcyhpbmQsIChmMVtpbmQsMV0qc3RkX3krbV95KS9tX3ksIGNvbD0yLCBsd2Q9MikJCQkJIyBmMQ0KDQpsZWdlbmQoInRvcGxlZnQiLCBpbnNldD1jKDAuMjIsMC4wMiksIGxlZ2VuZD1jKFRlWCgnT2JzZXJ2YXRpb25zIC0gaW50ZXJjZXB0IC0gJGZfMiQgLSAkZl8zJCAtICRmXzQkJyksVGVYKCckZl8xJCcpKSwgY29sPWMoZ3JleSgwLjQpLDIsMywiZ3JleSIpLCBsdHk9YyhOQSwxLDEsMSksIHBjaD1jKDIwLE5BLE5BLE5BKSwgbHdkPWMoMSwzLDMsMyksIGNleD0xLjQsIHhwZD1UUlVFLCBidHk9Im4iLCB5LmludGVyc3A9MSwgeC5pbnRlcnNwPTAuOCwgdGV4dC5mb250PTEsIG5jb2w9MSwgc2VnLmxlbj0xLjUpDQpgYGANCg0KUGxvdCBvZiB0aGUgbWVhbiBwb3N0ZXJpb3IgZnVuY3Rpb24gJGZfMiQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTUsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCnBhcihtYWk9YygxLCAwLjgyLCAwLjEsIDAuNDIpKQ0KDQpkYXRhX3llYXIgPC0gZGF0YVtkYXRhJHllYXIgJWluJSBzZXEoMTk2OSwxOTgxLDEpLF0NCmluZCA8LSBkYXRhX3llYXIkaWQNCmF4aXNfbGFiZWxzX2F0IDwtIGFnZ3JlZ2F0ZShkYXRhX3llYXIsIGJ5PWxpc3QoZGF0YV95ZWFyJHllYXIpLCBGVU49bWluKSRpZA0KDQpvYnMgPC0gKCh5W2luZF0taW50ZXJjZXB0WzFdLWYxW2luZCwxXS1mM1tpbmQsMV0tZjRbZGF0YSRkYXlfb2ZfeWVhcjIsMV1baW5kXSkqc3RkX3krbV95KS9tX3kNCnBsb3QoaW5kLCBvYnMsIHR5cGU9InAiLCBsdHk9MSwgcGNoPTIwLCBjZXg9MC42LCBjb2w9Z3JleSgwLjUpLCB4bGFiPSIiLCB5bGFiPSJQcm9wb3J0aW9uIG9mIGJpcnRocyBvdmVyIHRoZSBtZWFuIiwgY2V4LmxhYj0xLjUsIGNleC5heGlzPTEuNiwgeGF4dD0ibiIsIHlsaW09YygwLjg1LDEuMTUpKQ0KDQpheGlzKDEsIGF0PWF4aXNfbGFiZWxzX2F0LCBsYWJlbHM9YXMuY2hhcmFjdGVyKHNlcSgxOTY5LDE5ODEsMSkpLCB0aWNrPVRSVUUsIGNleC5heGlzPTEuNikNCg0KbGluZXMocmFuZ2UoaW5kKSwgYygxLDEpLCBsdHk9MiwgbHdkPTEpCQkJCQkJICAgICAgICAjIG1lYW4NCmxpbmVzKGluZCwgKGYyW2luZCwxXSpzdGRfeSttX3kpL21feSwgY29sPTMsIGx3ZD0yKQkgCQkgICMgZjINCg0KYWJsaW5lKHY9YXhpc19sYWJlbHNfYXQsIGx0eT0yLCBjb2w9Z3JleSgwLjcpKQ0KbGVnZW5kKCJ0b3BsZWZ0IiwgaW5zZXQ9YygwLjA1LDAuMDA1KSwgbGVnZW5kPWMoVGVYKCdPYnNlcnZhdGlvbnMgLSBpbnRlcmNlcHQgLSAkZl8xJCAtICRmXzMkIC0gJGZfNCQnKSxUZVgoJyRmXzIkJykpLCBjb2w9YyhncmV5KDAuNSksMyksIGx0eT1jKE5BLDEpLCBwY2g9YygyMCxOQSksIGx3ZD1jKDMsMyksIGNleD0xLjQsIHhwZD1UUlVFLCBidHk9Im4iLCB5LmludGVyc3A9MSwgeC5pbnRlcnNwPTAuOCwgdGV4dC5mb250PTEsIG5jb2w9MSwgc2VnLmxlbj0xLjMpDQpgYGANCg0KUGxvdCBvZiB0aGUgbWVhbiBwb3N0ZXJpb3IgZnVuY3Rpb24gJGZfMSArIGZfMiQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTUsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCnBhcihtYWk9YygxLCAwLjgyLCAwLjEsIDAuNDIpKQ0KDQpkYXRhX3llYXIgPC0gZGF0YVtkYXRhJHllYXIgJWluJSBzZXEoMTk2OSwxOTgxLDEpLF0NCmluZCA8LSBkYXRhX3llYXIkaWQNCmF4aXNfbGFiZWxzX2F0IDwtIGFnZ3JlZ2F0ZShkYXRhX3llYXIsIGJ5PWxpc3QoZGF0YV95ZWFyJHllYXIpLCBGVU49bWluKSRpZA0KDQpvYnMgPC0gKCh5W2luZF0taW50ZXJjZXB0WzFdLWYzW2luZCwxXS1mNFtkYXRhJGRheV9vZl95ZWFyMiwxXVtpbmRdKSpzdGRfeSttX3kpL21feQ0KcGxvdChpbmQsIG9icywgdHlwZT0icCIsIGx0eT0xLCBwY2g9MjAsIGNleD0wLjYsIGNvbD1ncmV5KDAuNSksIHhsYWI9IiIsIHlsYWI9IlByb3BvcnRpb24gb2YgYmlydGhzIG92ZXIgdGhlIG1lYW4iLCBjZXgubGFiPTEuNSwgY2V4LmF4aXM9MS42LCB4YXh0PSJuIiwgeWxpbT1jKDAuOCwxLjIpKQ0KDQpheGlzKDEsIGF0PWF4aXNfbGFiZWxzX2F0LCBsYWJlbHM9YXMuY2hhcmFjdGVyKHNlcSgxOTY5LDE5ODEsMSkpLCB0aWNrPVRSVUUsIGNleC5heGlzPTEuNikNCg0KbGluZXMocmFuZ2UoaW5kKSwgYygxLDEpLCBsdHk9MiwgbHdkPTEpCQkJCQkJICAgICAgICAgICAgICAgICAgICAjIG1lYW4NCmxpbmVzKGluZCwgKChmMVtpbmQsMV0rZjJbaW5kLDFdKSpzdGRfeSttX3kpL21feSwgY29sPTQsIGx3ZD0yKQkgCQkgICMgZjEgKyBmMg0KDQphYmxpbmUodj1heGlzX2xhYmVsc19hdCwgbHR5PTIsIGNvbD1ncmV5KDAuNykpDQpsZWdlbmQoInRvcGxlZnQiLCBpbnNldD1jKDAuMDUsMC4wMDUpLCBsZWdlbmQ9YyhUZVgoJ09ic2VydmF0aW9ucyAtIGludGVyY2VwdCAtICRmXzMkIC0gJGZfNCQnKSxUZVgoJyRmXzEgKyBmXzIkJykpLCBjb2w9YyhncmV5KDAuNSksNCksIGx0eT1jKE5BLDEpLCBwY2g9YygyMCxOQSksIGx3ZD1jKDMsMyksIGNleD0xLjQsIHhwZD1UUlVFLCBidHk9Im4iLCB5LmludGVyc3A9MSwgeC5pbnRlcnNwPTAuOCwgdGV4dC5mb250PTEsIG5jb2w9MSwgc2VnLmxlbj0xLjMpDQpgYGANCg0KUGxvdCBvZiB0aGUgcmVzaWR1YWxzDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTE1LCBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQpwYXIobWFpPWMoMSwgMC44MiwgMC4xLCAwLjQyKSkNCg0KZGF0YV95ZWFyIDwtIGRhdGFbZGF0YSR5ZWFyICVpbiUgc2VxKDE5NjksMTk4MSwxKSxdDQppbmQgPC0gZGF0YV95ZWFyJGlkDQpheGlzX2xhYmVsc19hdCA8LSBhZ2dyZWdhdGUoZGF0YV95ZWFyLCBieT1saXN0KGRhdGFfeWVhciR5ZWFyKSwgRlVOPW1pbikkaWQNCg0Kb2JzIDwtICgoeVtpbmRdLWludGVyY2VwdFsxXS1mMVtpbmQsMV0tZjJbaW5kLDFdLWYzW2luZCwxXS1mNFtkYXRhJGRheV9vZl95ZWFyMiwxXVtpbmRdKSpzdGRfeSttX3kpL21feQ0KcGxvdChpbmQsIG9icywgdHlwZT0icCIsIGx0eT0xLCBwY2g9MjAsIGNleD0wLjYsIGNvbD1ncmV5KDAuNSksIHhsYWI9IiIsIHlsYWI9IlByb3BvcnRpb24gb2YgYmlydGhzIG92ZXIgdGhlIG1lYW4iLCBjZXgubGFiPTEuNSwgY2V4LmF4aXM9MS42LCB4YXh0PSJuIiwgeWxpbT1jKDAuOCwxLjIpKQ0KDQpheGlzKDEsIGF0PWF4aXNfbGFiZWxzX2F0LCBsYWJlbHM9YXMuY2hhcmFjdGVyKHNlcSgxOTY5LDE5ODEsMSkpLCB0aWNrPVRSVUUsIGNleC5heGlzPTEuNikNCg0KbGluZXMocmFuZ2UoaW5kKSwgYygxLDEpLCBsdHk9MiwgbHdkPTEpCQkJCQkJICAgICAgICAgICAgICAgICAgICAjIG1lYW4NCg0KYWJsaW5lKHY9YXhpc19sYWJlbHNfYXQsIGx0eT0yLCBjb2w9Z3JleSgwLjcpKQ0KbGVnZW5kKCJ0b3BsZWZ0IiwgaW5zZXQ9YygwLjA1LDAuMDA1KSwgbGVnZW5kPWMoVGVYKCdPYnNlcnZhdGlvbnMgLSBpbnRlcmNlcHQgLSAkZl8xJCAtICRmXzIkIC0gJGZfMyQgLSAkZl80JCcpKSwgY29sPWMoZ3JleSgwLjUpLDQpLCBsdHk9YyhOQSwxKSwgcGNoPWMoMjAsTkEpLCBsd2Q9YygzLDMpLCBjZXg9MS40LCB4cGQ9VFJVRSwgYnR5PSJuIiwgeS5pbnRlcnNwPTEsIHguaW50ZXJzcD0wLjgsIHRleHQuZm9udD0xLCBuY29sPTEsIHNlZy5sZW49MS4zKQ0KYGBgDQoNCiMjIyMgTW9kZWwgZXZhbHVhdGlvbg0KDQpSZXNpZHVhbHMNCg0KYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmYgPC0gc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IGMoImYiKSkkc3VtbWFyeVssMV0NCnJlc1tbaV1dIDwtIHN0YW5kYXRhW1tpXV0keSAtIGYNCg0KZ2dwbG90KGFzLmRhdGEuZnJhbWUocmVzW1tpXV0pLCBhZXMocmVzW1tpXV0pKSAgKw0KICBnZW9tX2hpc3RvZ3JhbShjb2xvciA9ICd3aGl0ZScpICsNCiAgdGhlbWVfY2xhc3NpYygpDQpgYGANCg0KUm9vdCBtZWFuIHNxdWFyZWQgZXJyb3INCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCnJtc2VbaV0gPC0gc3FydChtZWFuKHJlc1tbaV1dXjIpKQ0Kcm1zZVtpXQ0KYGBgDQoNCkJheWVzaWFuICRSXjIkIChDb2VmZmljaWVudCBvZiBkZXRlcm1pbmF0aW9uKQ0KDQpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD00LCBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0Kbm9pc2UgPC0gYXMubWF0cml4KGZpdFtbaV1dLCBwYXJzID0gYygibm9pc2UiKSkNCnNkX2YgPC0gYXBwbHkoYXMubWF0cml4KGZpdFtbaV1dLCBwYXJzID0gYygiZiIpKSwgMSwgc2QpDQpSMiA8LSBzZF9mXjIvKHNkX2ZeMiArIG5vaXNlXjIpDQoNCmdncGxvdChhcy5kYXRhLmZyYW1lKFIyKSwgYWVzKFIyKSkgICsNCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3IgPSAnd2hpdGUnKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KYGBgDQoNCk1lZGlhbiBvZiAkUl4yJA0KDQpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD00LCBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KZVIyW2ldIDwtIG1lZGlhbihSMikNCmVSMltpXQ0KYGBgDQoNCkxvZyBwcmVkaWN0aXZlIGRlbnNpdHkgKGxwZCkNCg0KYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxwZCA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygibG9nX2xpayIpKSRzdW1tYXJ5WywxXQ0KDQpnZ3Bsb3QoYXMuZGF0YS5mcmFtZShscGQpLCBhZXMobHBkKSkgICsNCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3IgPSAnd2hpdGUnKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KYGBgDQoNCk1lZGlhbiBvZiBscGQNCg0KYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmVscGRbaV0gPC0gbWVkaWFuKGxwZCkNCmVscGRbaV0NCmBgYA0KDQojIyMjIERpYWdub3Npcw0KDQoqKlNtb290aCB0cmVuZCBmdW5jdGlvbiAkZl8xJCoqDQoNCjEuIEVzdGltYXRlZCBsZW5ndGhzY2FsZSAkXGhhdHtsfSQgIA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mMV9oYXRbaV0gPC0gcm91bmQoc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9ICJsc2NhbGVbMV0iKSRzdW1tYXJ5WywxXSwgMikNCmxfZjFfaGF0W2ldDQpgYGANCg0KMi4gQ2hlY2sgd2hldGhlciAkXGhhdHtsfSQgaXMgZXF1YWwgdG8gb3IgZ3JlYXRlciB0aGFuIGBsX2YxYCAodGhlIG1pbmltdW0gJGwkIHRoYXQgY2FuIGJlIGFjY3VyYXRlbHkgZml0dGVkIGRldGVybWluZWQgYnkgdGhlICRtJCB1c2VkKQ0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mMV9oYXRbaV0gPj0gbF9mMVtpXQ0KYGBgDQoNCioqWWVhcmx5IHBlcmlvZGljIGVmZmVjdHMgZnVuY3Rpb24gJGZfMiQqKg0KDQoxLiBFc3RpbWF0ZWQgbGVuZ3Roc2NhbGUgJFxoYXR7bH0kICANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjJfaGF0W2ldIDwtIHJvdW5kKHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSAibHNjYWxlWzJdIikkc3VtbWFyeVssMV0sIDIpDQpsX2YyX2hhdFtpXQ0KYGBgDQoNCjIuIENoZWNrIHdoZXRoZXIgJFxoYXR7bH0kIGlzIGVxdWFsIHRvIG9yIGdyZWF0ZXIgdGhhbiBgbF9mMmAgKHRoZSBtaW5pbXVtICRsJCB0aGF0IGNhbiBiZSBhY2N1cmF0ZWx5IGZpdHRlZCBkZXRlcm1pbmVkIGJ5IHRoZSAkbSQgdXNlZCkNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjJfaGF0W2ldID49IGxfZjJbaV0NCmBgYA0KDQoqKldlZWtseSBwZXJpb2RpYyBlZmZlY3RzIGZ1bmN0aW9uICRmXzMkKioNCg0KMS4gRXN0aW1hdGVkIGxlbmd0aHNjYWxlICRcaGF0e2x9JCAgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpsX2YzX2hhdFtpXSA8LSByb3VuZChzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gImxzY2FsZVszXSIpJHN1bW1hcnlbLDFdLCAyKQ0KbF9mM19oYXRbaV0NCmBgYA0KDQoyLiBDaGVjayB3aGV0aGVyICRcaGF0e2x9JCBpcyBlcXVhbCB0byBvciBncmVhdGVyIHRoYW4gYGxfZjNgICh0aGUgbWluaW11bSAkbCQgdGhhdCBjYW4gYmUgYWNjdXJhdGVseSBmaXR0ZWQgZGV0ZXJtaW5lZCBieSB0aGUgJG0kIHVzZWQpDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpsX2YzX2hhdFtpXSA+PSBsX2YzW2ldDQpgYGANCg0KKipTdW1tYXJ5IHRhYmxlKioNCg0KYGBge3IgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NSwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZWNobz1GQUxTRX0NCmRpYWdub3Npc1tbaV1dIDwtIGRhdGEuZnJhbWUoaXRlcj0gcmVwKGksIDMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR1BfZnVuYz0gYygiZjEiLCAiZjIiLCAiZjMiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGw9IHJvdW5kKGMobF9mMVtpXSwgbF9mMltpXSwgbF9mM1tpXSksIDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYz0gcm91bmQoYyhjX2YxW2ldLCBOQSwgTkEpLCAyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG09IGMobV9mMVtpXSwgbV9mMltpXSwgbV9mM1tpXSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsX2hhdD0gcm91bmQoYyhsX2YxX2hhdFtpXSwgbF9mMl9oYXRbaV0sIGxfZjNfaGF0W2ldKSwgMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnbF9oYXQgPiBsJyA9IGMobF9mMV9oYXRbaV0gPj0gbF9mMVtpXSwgbF9mMl9oYXRbaV0gPj0gbF9mMltpXSwgbF9mM19oYXRbaV0gPj0gbF9mM1tpXSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByc21lID0gcm91bmQocmVwKHJtc2VbaV0sIDMpLCAzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFIyID0gcm91bmQocmVwKGVSMltpXSwgMyksIDMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxwZCA9IHJvdW5kKHJlcChlbHBkW2ldLCAzKSwgMykNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkNCm5hbWVzKGRpYWdub3Npc1tbaV1dKSA8LSBjKCJpdGVyIiwgIkdQX2Z1bmMiLCAibCIsICJjIiwgIm0iLCAibF9oYXQiLCAibF9oYXQgPiBsIiwgInJtc2UiLCAiUjIiLCAiZWxwZCIpDQpkaWFnbm9zaXNbW2ldXQ0KYGBgDQoNCg0KIyMjIEl0ZXJhdGlvbiAzDQoNCkl0ZXJhdGlvbiBpbmRleA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KaSA8LSAzDQpgYGANCg0KIyMjIyBTZXR0aW5nICRtJCwgJGwkIGFuZCAkYyQNCg0KKipTbW9vdGggdHJlbmQgZnVuY3Rpb24gJGZfMSQqKg0KDQoxLiBVcGRhdGluZyAkbCQgd2l0aCBpdHMgZXN0aW1hdGUgJFxoYXR7bH0kIGluIHRoZSBzZWNvbmQgaXRlcmF0aW9uDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpsX2YxW2ldIDwtIGxfZjFfaGF0W2ktMV0NCmxfZjFbaV0NCmBgYA0KDQoyLiBUaGUgYm91bmRhcnkgZmFjdG9yICRjJCBoYXMgdG8gZnVsZmlsbCAkYyBcLCBcZ2VxIFwsIDAuOTcgKyAxLjQ1IFwsIFxmcmFje2x9e1N9JA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KMC45NyArIDEuNDUqbF9mMVtpXS9TDQpgYGANCg0KVGhlbiwgJGMkIGlzIHNldCB0bw0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KY19mMVtpXSA8LSAxLjUNCmNfZjFbaV0NCmBgYA0KDQozLiBUaGUgbnVtYmVyIG9mIGJhc2lzIGZ1bmN0aW9ucyAkbSQgYXMgYSBmdW5jdGlvbiBvZiAkbCQ6ICAkXDsgbT0gMS43MyBcLCBcZnJhY3tjfXsobC9TKV57MS4wNX19JA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KaWYoMS43MyAqIGNfZjFbaV0vKGxfZjFbaV0vUyleMS4wNSA8IDUpIG1fZjFbaV0gPC0gNSBlbHNlIG1fZjFbaV0gPC0gY2VpbGluZygxLjczICogY19mMVtpXS8obF9mMVtpXS9TKV4xLjA1KQ0KbV9mMVtpXQ0KYGBgDQoNCioqWWVhcmx5IHBlcmlvZGljIGVmZmVjdHMgZnVuY3Rpb24gJGZfMiQqKg0KDQoxLiBVcGRhdGluZyAkbCQgd2l0aCBpdHMgZXN0aW1hdGUgJFxoYXR7bH0kIGluIHRoZSBzZWNvbmQgaXRlcmF0aW9uDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpsX2YyW2ldIDwtIGxfZjJfaGF0W2ktMV0NCmxfZjJbaV0NCmBgYA0KDQoyLiBOdW1iZXIgb2YgYmFzaXMgZnVuY3Rpb25zICRtJCBhcyBhIGZ1bmN0aW9uIG9mICRsJDogICRcOyBtPSAzLjMxIFwsIFxmcmFjezF9e2xeezEuMDV9fSQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmlmKDMuMzEgKiAxL2xfZjJbaV1eMS4wNSA8IDUpIG1fZjJbaV0gPC0gNSBlbHNlIG1fZjJbaV0gPC0gY2VpbGluZygzLjMxICogMS9sX2YyW2ldXjEuMDUpDQptX2YyW2ldDQpgYGANCg0KKipXZWVrbHkgcGVyaW9kaWMgZWZmZWN0cyBmdW5jdGlvbiAkZl8zJCoqDQoNCjEuIFVwZGF0aW5nICRsJCB3aXRoIGl0cyBlc3RpbWF0ZSAkXGhhdHtsfSQgaW4gdGhlIHNlY29uZCBpdGVyYXRpb24NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjNbaV0gPC0gbF9mM19oYXRbaS0xXQ0KbF9mM1tpXQ0KYGBgDQoNCjIuIE51bWJlciBvZiBiYXNpcyBmdW5jdGlvbnMgJG0kIGFzIGEgZnVuY3Rpb24gb2YgJGwkOiAgJFw7IG09IDMuMzEgXCwgXGZyYWN7MX17bF57MS4wNX19JA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KaWYoMy4zMSAqIDEvbF9mM1tpXV4xLjA1IDwgNSkgbV9mM1tpXSA8LSA1IGVsc2UgbV9mM1tpXSA8LSBjZWlsaW5nKDMuMzEgKiAxL2xfZjNbaV1eMS4wNSkNCm1fZjNbaV0NCmBgYA0KDQojIyMjIERhdGEgdG8gU3Rhbg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0Kc3RhbmRhdGFbW2ldXSA8LSBsaXN0KE1fZjE9IG1fZjFbaV0sIA0KICAgICAgICAgICAgICAgICBjX2YxPSBjX2YxW2ldLCANCiAgICAgICAgICAgICAgICAgSl9mMj0gbV9mMltpXSwgDQogICAgICAgICAgICAgICAgIEpfZjM9IG1fZjNbaV0sIA0KICAgICAgICAgICAgICAgICB4PSB4WywxXSwgDQogICAgICAgICAgICAgICAgIHk9IHlbLDFdLCANCiAgICAgICAgICAgICAgICAgTj0gbGVuZ3RoKHgpLCANCiAgICAgICAgICAgICAgICAgcGVyaW9kX3llYXI9IHBlcmlvZF95ZWFyLCANCiAgICAgICAgICAgICAgICAgcGVyaW9kX3dlZWs9IHBlcmlvZF93ZWVrLA0KICAgICAgICAgICAgICAgICBkYXlfb2ZfeWVhcjI9IGRheV9vZl95ZWFyMg0KKQ0Kc3RyKHN0YW5kYXRhW1tpXV0pDQpgYGANCg0KIyMjIyBNb2RlbCBmaXR0aW5nDQoNCkNvbXBpbGluZyB0aGUgbW9kZWwNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1UUlVFLCBldmFsPUZBTFNFfQ0KIyBiaXJ0aGRheV9tb2QgPC0gY21kc3RhbnI6OmNtZHN0YW5fbW9kZWwoc3Rhbl9maWxlID0gInN0YW5jb2RlX2RlZi5zdGFuIikNCmBgYA0KDQpNb2RlbCBzYW1wbGluZw0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBldmFsPVRSVUV9DQojIGxvYWQoImZpdC5yRGF0YSIpDQpgYGANCg0KYGBge3Igd2Fybj1UUlVFLCBtZXNzYWdlPUZBTFNFLCBldmFsPUZBTFNFfQ0KIyBmaXRbW2ldXSA8LSBiaXJ0aGRheV9tb2Qkc2FtcGxlKGRhdGE9IHN0YW5kYXRhW1tpXV0sIGl0ZXJfd2FybXVwPTIwMCwgaXRlcl9zYW1wbGluZz0yMDAsIGNoYWlucz00LCB0aGluPTQsIGluaXQ9MC41LCBhZGFwdF9kZWx0YT0wLjksIHNhdmVfd2FybXVwPUZBTFNFKQ0KIyBmaXRbW2ldXSA8LSByc3Rhbjo6cmVhZF9zdGFuX2NzdihmaXRbW2ldXSRvdXRwdXRfZmlsZXMoKSkNCg0KIyBzYXZlKGZpdCwgZmlsZT0iZml0LnJEYXRhIikNCmBgYA0KDQpTdW1tYXJpZXMgb2YgdmFyaWFibGUgZXN0aW1hdGVzDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGV2YWw9VFJVRX0NCnBhcmFtID0gYygiaW50ZXJjZXB0IiwibHNjYWxlWzFdIiwibHNjYWxlWzJdIiwibHNjYWxlWzNdIiwiZ3BzY2FsZVsxXSIsImdwc2NhbGVbMl0iLCJncHNjYWxlWzNdIiwibm9pc2UiLCJzaWdtYV9mNCIpDQpzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gcGFyYW0sIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSksIGRpZ2l0c19zdW1tYXJ5ID0gNCkkc3VtbWFyeQ0KYGBgDQoNClNpbXVsYXRpb24gY2hhaW5zIGZvciB0aGUgdmFyaWFibGVzIGFmdGVyIHdhcm11cA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xNSwgZXZhbD1UUlVFfQ0KdHJhY2VwbG90KGZpdFtbaV1dLCBwYXJzID0gcGFyYW0sIGluY2x1ZGUgPSBUUlVFLCB1bmNvbnN0cmFpbiA9IEZBTFNFLCBpbmNfd2FybXVwID0gRkFMU0UsIHdpbmRvdyA9IE5VTEwsIG5yb3cgPSBOVUxMLCBuY29sID0gTlVMTCkNCmBgYA0KDQpQbG90IG9mIHRoZSBtZWFuIHBvc3RlcmlvciBmdW5jdGlvbiAkZl8xJA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xNSwgZmlnLmFsaWduPSdjZW50ZXInLCBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQpmIDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJmIiksIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSkpJHN1bW1hcnkNCmludGVyY2VwdCA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygiaW50ZXJjZXB0IiksIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSkpJHN1bW1hcnkNCmYxIDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJmMSIpLCBwcm9icyA9IGMoMC4wMjUsIDAuNSwgMC45NzUpKSRzdW1tYXJ5DQpmMiA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygiZjIiKSwgcHJvYnMgPSBjKDAuMDI1LCAwLjUsIDAuOTc1KSkkc3VtbWFyeQ0KZjMgPC0gc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IGMoImYzIiksIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSkpJHN1bW1hcnkNCmY0IDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJmNCIpLCBwcm9icyA9IGMoMC4wMjUsIDAuNSwgMC45NzUpKSRzdW1tYXJ5DQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTUsIGZpZy5hbGlnbj0nY2VudGVyJywgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KcGFyKG1haT1jKDEsIDAuODIsIDAuMSwgMC40MikpDQoNCmluZCA8LSBkYXRhJGlkDQpsYWJlbHNfYXQgPSBhZ2dyZWdhdGUoZGF0YSwgYnk9bGlzdChkYXRhJHllYXIpLCBGVU49bWluKSRpZA0KDQpvYnNfcGx0IDwtICgoeVtpbmRdLWludGVyY2VwdFsxXS1mMltpbmQsMV0tZjNbaW5kLDFdLWY0W2RhdGEkZGF5X29mX3llYXIyLDFdW2luZF0pKnN0ZF95K21feSkvbV95DQpwbG90KGluZCwgb2JzX3BsdCwgdHlwZT0icCIsIHBjaD0yMCwgYmc9Z3JleSgwLjQpLCBjZXg9MC42LCBjb2w9Z3JleSgwLjUpLCB4bGFiPSIiLCB5bGFiPSIiLCBsd2Q9MSwgeWxpbT1jKDAuOCwxLjIpLCBtZ3A9YygzLjUsIDEsIDApLCBmcmFtZS5wbG90PVRSVUUsIHlheHM9InIiLCBjZXguYXhpcz0xLjYsIGNleC5sYWI9MS42LCBsYXM9MSwgeGF4dD0ibiIsIHlheHQ9Im4iLCBmZz1ncmV5KDAuNSksIGZhbWlseT0ic2VyaWYiKQ0KDQpheGlzKDEsIGF0PWxhYmVsc19hdCwgYygiMTk2OSIsIjE5NzAiLCIxOTcxIiwiMTk3MiIsIjE5NzMiLCIxOTc0IiwiMTk3NSIsIjE5NzYiLCIxOTc3IiwiMTk3OCIsIjE5NzkiLCIxOTgwIiwiMTk4MSIsIjE5ODIiLCIxOTgzIiwiMTk4NCIsIjE5ODUiLCIxOTg2IiwiMTk4NyIsIjE5ODgiKSwgdGljaz1UUlVFLCBsdHk9MSwgbWdwPWMoMywgMSwgMCksIGxhcz0xLCBjZXguYXhpcz0xLjYsIGZvbnQ9MSwgY29sPWdyZXkoMC41KSwgY29sLnRpY2tzPWdyZXkoMC4zKSwgZmFtaWx5PSIiKQ0KYXhpcygyLCBhdD1OVUxMLCBsYWJlbHM9VFJVRSwgdGljaz1UUlVFLCBsdHk9MSwgbWdwPWMoMywgMC43LCAwKSwgbGFzPTEsIGNleC5heGlzPTEuNiwgZm9udD01LCBjb2w9Z3JleSgwLjUpLCBjb2wudGlja3M9Z3JleSgwLjMpKQ0KdGl0bGUoeGxhYj0iWWVhciIsIG1ncD1jKDMsIDEsIDApLCBjZXgubGFiPTEuNiwgbGFzPTEpDQp0aXRsZSh5bGFiPSJQcm9wb3J0aW9uIG9mIGJpcnRocyBvdmVyIHRoZSBtZWFuIiwgbWdwPWMoMywgMC43LCAwKSwgY2V4LmxhYj0xLjYsIGxhcz0xKQ0KDQphYmxpbmUoaD0xLCBsdHk9MikJCQkJCQkJCQkJCQkgICAgICAgICAgICAgICAgIyBtZWFuDQpsaW5lcyhpbmQsIChmMVtpbmQsMV0qc3RkX3krbV95KS9tX3ksIGNvbD0yLCBsd2Q9MikJCQkJIyBmMQ0KDQpsZWdlbmQoInRvcGxlZnQiLCBpbnNldD1jKDAuMjIsMC4wMiksIGxlZ2VuZD1jKFRlWCgnT2JzZXJ2YXRpb25zIC0gaW50ZXJjZXB0IC0gJGZfMiQgLSAkZl8zJCAtICRmXzQkJyksVGVYKCckZl8xJCcpKSwgY29sPWMoZ3JleSgwLjQpLDIsMywiZ3JleSIpLCBsdHk9YyhOQSwxLDEsMSksIHBjaD1jKDIwLE5BLE5BLE5BKSwgbHdkPWMoMSwzLDMsMyksIGNleD0xLjQsIHhwZD1UUlVFLCBidHk9Im4iLCB5LmludGVyc3A9MSwgeC5pbnRlcnNwPTAuOCwgdGV4dC5mb250PTEsIG5jb2w9MSwgc2VnLmxlbj0xLjUpDQpgYGANCg0KUGxvdCBvZiB0aGUgbWVhbiBwb3N0ZXJpb3IgZnVuY3Rpb24gJGZfMiQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTUsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCnBhcihtYWk9YygxLCAwLjgyLCAwLjEsIDAuNDIpKQ0KDQpkYXRhX3llYXIgPC0gZGF0YVtkYXRhJHllYXIgJWluJSBzZXEoMTk2OSwxOTgxLDEpLF0NCmluZCA8LSBkYXRhX3llYXIkaWQNCmF4aXNfbGFiZWxzX2F0IDwtIGFnZ3JlZ2F0ZShkYXRhX3llYXIsIGJ5PWxpc3QoZGF0YV95ZWFyJHllYXIpLCBGVU49bWluKSRpZA0KDQpvYnMgPC0gKCh5W2luZF0taW50ZXJjZXB0WzFdLWYxW2luZCwxXS1mM1tpbmQsMV0tZjRbZGF0YSRkYXlfb2ZfeWVhcjIsMV1baW5kXSkqc3RkX3krbV95KS9tX3kNCnBsb3QoaW5kLCBvYnMsIHR5cGU9InAiLCBsdHk9MSwgcGNoPTIwLCBjZXg9MC42LCBjb2w9Z3JleSgwLjUpLCB4bGFiPSIiLCB5bGFiPSJQcm9wb3J0aW9uIG9mIGJpcnRocyBvdmVyIHRoZSBtZWFuIiwgY2V4LmxhYj0xLjUsIGNleC5heGlzPTEuNiwgeGF4dD0ibiIsIHlsaW09YygwLjg1LDEuMTUpKQ0KDQpheGlzKDEsIGF0PWF4aXNfbGFiZWxzX2F0LCBsYWJlbHM9YXMuY2hhcmFjdGVyKHNlcSgxOTY5LDE5ODEsMSkpLCB0aWNrPVRSVUUsIGNleC5heGlzPTEuNikNCg0KbGluZXMocmFuZ2UoaW5kKSwgYygxLDEpLCBsdHk9MiwgbHdkPTEpCQkJCQkJICAgICAgICAjIG1lYW4NCmxpbmVzKGluZCwgKGYyW2luZCwxXSpzdGRfeSttX3kpL21feSwgY29sPTMsIGx3ZD0yKQkgCQkgICMgZjINCg0KYWJsaW5lKHY9YXhpc19sYWJlbHNfYXQsIGx0eT0yLCBjb2w9Z3JleSgwLjcpKQ0KbGVnZW5kKCJ0b3BsZWZ0IiwgaW5zZXQ9YygwLjA1LDAuMDA1KSwgbGVnZW5kPWMoVGVYKCdPYnNlcnZhdGlvbnMgLSBpbnRlcmNlcHQgLSAkZl8xJCAtICRmXzMkIC0gJGZfNCQnKSxUZVgoJyRmXzIkJykpLCBjb2w9YyhncmV5KDAuNSksMyksIGx0eT1jKE5BLDEpLCBwY2g9YygyMCxOQSksIGx3ZD1jKDMsMyksIGNleD0xLjQsIHhwZD1UUlVFLCBidHk9Im4iLCB5LmludGVyc3A9MSwgeC5pbnRlcnNwPTAuOCwgdGV4dC5mb250PTEsIG5jb2w9MSwgc2VnLmxlbj0xLjMpDQpgYGANCg0KUGxvdCBvZiB0aGUgbWVhbiBwb3N0ZXJpb3IgZnVuY3Rpb24gJGZfMSArIGZfMiQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTUsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCnBhcihtYWk9YygxLCAwLjgyLCAwLjEsIDAuNDIpKQ0KDQpkYXRhX3llYXIgPC0gZGF0YVtkYXRhJHllYXIgJWluJSBzZXEoMTk2OSwxOTgxLDEpLF0NCmluZCA8LSBkYXRhX3llYXIkaWQNCmF4aXNfbGFiZWxzX2F0IDwtIGFnZ3JlZ2F0ZShkYXRhX3llYXIsIGJ5PWxpc3QoZGF0YV95ZWFyJHllYXIpLCBGVU49bWluKSRpZA0KDQpvYnMgPC0gKCh5W2luZF0taW50ZXJjZXB0WzFdLWYzW2luZCwxXS1mNFtkYXRhJGRheV9vZl95ZWFyMiwxXVtpbmRdKSpzdGRfeSttX3kpL21feQ0KcGxvdChpbmQsIG9icywgdHlwZT0icCIsIGx0eT0xLCBwY2g9MjAsIGNleD0wLjYsIGNvbD1ncmV5KDAuNSksIHhsYWI9IiIsIHlsYWI9IlByb3BvcnRpb24gb2YgYmlydGhzIG92ZXIgdGhlIG1lYW4iLCBjZXgubGFiPTEuNSwgY2V4LmF4aXM9MS42LCB4YXh0PSJuIiwgeWxpbT1jKDAuOCwxLjIpKQ0KDQpheGlzKDEsIGF0PWF4aXNfbGFiZWxzX2F0LCBsYWJlbHM9YXMuY2hhcmFjdGVyKHNlcSgxOTY5LDE5ODEsMSkpLCB0aWNrPVRSVUUsIGNleC5heGlzPTEuNikNCg0KbGluZXMocmFuZ2UoaW5kKSwgYygxLDEpLCBsdHk9MiwgbHdkPTEpCQkJCQkJICAgICAgICAgICAgICAgICAgICAjIG1lYW4NCmxpbmVzKGluZCwgKChmMVtpbmQsMV0rZjJbaW5kLDFdKSpzdGRfeSttX3kpL21feSwgY29sPTQsIGx3ZD0yKQkgCQkgICMgZjEgKyBmMg0KDQphYmxpbmUodj1heGlzX2xhYmVsc19hdCwgbHR5PTIsIGNvbD1ncmV5KDAuNykpDQpsZWdlbmQoInRvcGxlZnQiLCBpbnNldD1jKDAuMDUsMC4wMDUpLCBsZWdlbmQ9YyhUZVgoJ09ic2VydmF0aW9ucyAtIGludGVyY2VwdCAtICRmXzMkIC0gJGZfNCQnKSxUZVgoJyRmXzEgKyBmXzIkJykpLCBjb2w9YyhncmV5KDAuNSksNCksIGx0eT1jKE5BLDEpLCBwY2g9YygyMCxOQSksIGx3ZD1jKDMsMyksIGNleD0xLjQsIHhwZD1UUlVFLCBidHk9Im4iLCB5LmludGVyc3A9MSwgeC5pbnRlcnNwPTAuOCwgdGV4dC5mb250PTEsIG5jb2w9MSwgc2VnLmxlbj0xLjMpDQpgYGANCg0KUGxvdCBvZiB0aGUgcmVzaWR1YWxzDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTE1LCBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQpwYXIobWFpPWMoMSwgMC44MiwgMC4xLCAwLjQyKSkNCg0KZGF0YV95ZWFyIDwtIGRhdGFbZGF0YSR5ZWFyICVpbiUgc2VxKDE5NjksMTk4MSwxKSxdDQppbmQgPC0gZGF0YV95ZWFyJGlkDQpheGlzX2xhYmVsc19hdCA8LSBhZ2dyZWdhdGUoZGF0YV95ZWFyLCBieT1saXN0KGRhdGFfeWVhciR5ZWFyKSwgRlVOPW1pbikkaWQNCg0Kb2JzIDwtICgoeVtpbmRdLWludGVyY2VwdFsxXS1mMVtpbmQsMV0tZjJbaW5kLDFdLWYzW2luZCwxXS1mNFtkYXRhJGRheV9vZl95ZWFyMiwxXVtpbmRdKSpzdGRfeSttX3kpL21feQ0KcGxvdChpbmQsIG9icywgdHlwZT0icCIsIGx0eT0xLCBwY2g9MjAsIGNleD0wLjYsIGNvbD1ncmV5KDAuNSksIHhsYWI9IiIsIHlsYWI9IlByb3BvcnRpb24gb2YgYmlydGhzIG92ZXIgdGhlIG1lYW4iLCBjZXgubGFiPTEuNSwgY2V4LmF4aXM9MS42LCB4YXh0PSJuIiwgeWxpbT1jKDAuOCwxLjIpKQ0KDQpheGlzKDEsIGF0PWF4aXNfbGFiZWxzX2F0LCBsYWJlbHM9YXMuY2hhcmFjdGVyKHNlcSgxOTY5LDE5ODEsMSkpLCB0aWNrPVRSVUUsIGNleC5heGlzPTEuNikNCg0KbGluZXMocmFuZ2UoaW5kKSwgYygxLDEpLCBsdHk9MiwgbHdkPTEpCQkJCQkJICAgICAgICAgICAgICAgICAgICAjIG1lYW4NCg0KYWJsaW5lKHY9YXhpc19sYWJlbHNfYXQsIGx0eT0yLCBjb2w9Z3JleSgwLjcpKQ0KbGVnZW5kKCJ0b3BsZWZ0IiwgaW5zZXQ9YygwLjA1LDAuMDA1KSwgbGVnZW5kPWMoVGVYKCdPYnNlcnZhdGlvbnMgLSBpbnRlcmNlcHQgLSAkZl8xJCAtICRmXzIkIC0gJGZfMyQgLSAkZl80JCcpKSwgY29sPWMoZ3JleSgwLjUpLDQpLCBsdHk9YyhOQSwxKSwgcGNoPWMoMjAsTkEpLCBsd2Q9YygzLDMpLCBjZXg9MS40LCB4cGQ9VFJVRSwgYnR5PSJuIiwgeS5pbnRlcnNwPTEsIHguaW50ZXJzcD0wLjgsIHRleHQuZm9udD0xLCBuY29sPTEsIHNlZy5sZW49MS4zKQ0KYGBgDQoNCiMjIyMgTW9kZWwgZXZhbHVhdGlvbg0KDQpSZXNpZHVhbHMNCg0KYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmYgPC0gc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IGMoImYiKSkkc3VtbWFyeVssMV0NCnJlc1tbaV1dIDwtIHN0YW5kYXRhW1tpXV0keSAtIGYNCg0KZ2dwbG90KGFzLmRhdGEuZnJhbWUocmVzW1tpXV0pLCBhZXMocmVzW1tpXV0pKSAgKw0KICBnZW9tX2hpc3RvZ3JhbShjb2xvciA9ICd3aGl0ZScpICsNCiAgdGhlbWVfY2xhc3NpYygpDQpgYGANCg0KUm9vdCBtZWFuIHNxdWFyZWQgZXJyb3INCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCnJtc2VbaV0gPC0gc3FydChtZWFuKHJlc1tbaV1dXjIpKQ0Kcm1zZVtpXQ0KYGBgDQoNCkJheWVzaWFuICRSXjIkIChDb2VmZmljaWVudCBvZiBkZXRlcm1pbmF0aW9uKQ0KDQpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD00LCBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0Kbm9pc2UgPC0gYXMubWF0cml4KGZpdFtbaV1dLCBwYXJzID0gYygibm9pc2UiKSkNCnNkX2YgPC0gYXBwbHkoYXMubWF0cml4KGZpdFtbaV1dLCBwYXJzID0gYygiZiIpKSwgMSwgc2QpDQpSMiA8LSBzZF9mXjIvKHNkX2ZeMiArIG5vaXNlXjIpDQoNCmdncGxvdChhcy5kYXRhLmZyYW1lKFIyKSwgYWVzKFIyKSkgICsNCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3IgPSAnd2hpdGUnKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KYGBgDQoNCk1lZGlhbiBvZiAkUl4yJA0KDQpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD00LCBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KZVIyW2ldIDwtIG1lZGlhbihSMikNCmVSMltpXQ0KYGBgDQoNCkxvZyBwcmVkaWN0aXZlIGRlbnNpdHkgKGxwZCkNCg0KYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxwZCA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygibG9nX2xpayIpKSRzdW1tYXJ5WywxXQ0KDQpnZ3Bsb3QoYXMuZGF0YS5mcmFtZShscGQpLCBhZXMobHBkKSkgICsNCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3IgPSAnd2hpdGUnKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KYGBgDQoNCk1lZGlhbiBvZiBscGQNCg0KYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmVscGRbaV0gPC0gbWVkaWFuKGxwZCkNCmVscGRbaV0NCmBgYA0KDQojIyMjIERpYWdub3Npcw0KDQoqKlNtb290aCB0cmVuZCBmdW5jdGlvbiAkZl8xJCoqDQoNCjEuIEVzdGltYXRlZCBsZW5ndGhzY2FsZSAkXGhhdHtsfSQgIA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mMV9oYXRbaV0gPC0gcm91bmQoc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9ICJsc2NhbGVbMV0iKSRzdW1tYXJ5WywxXSwgMikNCmxfZjFfaGF0W2ldDQpgYGANCg0KMi4gQ2hlY2sgd2hldGhlciAkXGhhdHtsfSQgaXMgZXF1YWwgdG8gb3IgZ3JlYXRlciB0aGFuIGBsX2YxYCAodGhlIG1pbmltdW0gJGwkIHRoYXQgY2FuIGJlIGFjY3VyYXRlbHkgZml0dGVkIGRldGVybWluZWQgYnkgdGhlICRtJCB1c2VkKQ0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mMV9oYXRbaV0gPj0gbF9mMVtpXQ0KYGBgDQoNCioqWWVhcmx5IHBlcmlvZGljIGVmZmVjdHMgZnVuY3Rpb24gJGZfMiQqKg0KDQoxLiBFc3RpbWF0ZWQgbGVuZ3Roc2NhbGUgJFxoYXR7bH0kICANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjJfaGF0W2ldIDwtIHJvdW5kKHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSAibHNjYWxlWzJdIikkc3VtbWFyeVssMV0sIDIpDQpsX2YyX2hhdFtpXQ0KYGBgDQoNCjIuIENoZWNrIHdoZXRoZXIgJFxoYXR7bH0kIGlzIGVxdWFsIHRvIG9yIGdyZWF0ZXIgdGhhbiBgbF9mMmAgKHRoZSBtaW5pbXVtICRsJCB0aGF0IGNhbiBiZSBhY2N1cmF0ZWx5IGZpdHRlZCBkZXRlcm1pbmVkIGJ5IHRoZSAkbSQgdXNlZCkNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjJfaGF0W2ldID49IGxfZjJbaV0NCmBgYA0KDQoqKldlZWtseSBwZXJpb2RpYyBlZmZlY3RzIGZ1bmN0aW9uICRmXzMkKioNCg0KMS4gRXN0aW1hdGVkIGxlbmd0aHNjYWxlICRcaGF0e2x9JCAgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpsX2YzX2hhdFtpXSA8LSByb3VuZChzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gImxzY2FsZVszXSIpJHN1bW1hcnlbLDFdLCAyKQ0KbF9mM19oYXRbaV0NCmBgYA0KDQoyLiBDaGVjayB3aGV0aGVyICRcaGF0e2x9JCBpcyBlcXVhbCB0byBvciBncmVhdGVyIHRoYW4gYGxfZjNgICh0aGUgbWluaW11bSAkbCQgdGhhdCBjYW4gYmUgYWNjdXJhdGVseSBmaXR0ZWQgZGV0ZXJtaW5lZCBieSB0aGUgJG0kIHVzZWQpDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpsX2YzX2hhdFtpXSA+PSBsX2YzW2ldDQpgYGANCg0KKipTdW1tYXJ5IHRhYmxlKioNCg0KYGBge3IgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NSwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZWNobz1GQUxTRX0NCmRpYWdub3Npc1tbaV1dIDwtIGRhdGEuZnJhbWUoaXRlcj0gcmVwKGksMyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHUF9mdW5jPSBjKCJmMSIsICJmMiIsICJmMyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbD0gcm91bmQoYyhsX2YxW2ldLCBsX2YyW2ldLCBsX2YzW2ldKSwgMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjPSByb3VuZChjKGNfZjFbaV0sIE5BLCBOQSksIDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbT0gYyhtX2YxW2ldLCBtX2YyW2ldLCBtX2YzW2ldKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxfaGF0PSByb3VuZChjKGxfZjFfaGF0W2ldLCBsX2YyX2hhdFtpXSwgbF9mM19oYXRbaV0pLCAyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdsX2hhdCA+IGwnID0gYyhsX2YxX2hhdFtpXSA+PSBsX2YxW2ldLCBsX2YyX2hhdFtpXSA+PSBsX2YyW2ldLCBsX2YzX2hhdFtpXSA+PSBsX2YzW2ldKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJzbWUgPSByb3VuZChyZXAocm1zZVtpXSwgMyksIDMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUjIgPSByb3VuZChyZXAoZVIyW2ldLCAzKSwgMyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHBkID0gcm91bmQocmVwKGVscGRbaV0sIDMpLCAzKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQ0KbmFtZXMoZGlhZ25vc2lzW1tpXV0pIDwtIGMoIml0ZXIiLCAiR1BfZnVuYyIsICJsIiwgImMiLCAibSIsICJsX2hhdCIsICJsX2hhdCA+IGwiLCAicm1zZSIsICJSMiIsICJlbHBkIikNCmRpYWdub3Npc1tbaV1dDQpgYGANCg0KDQojIyMgSXRlcmF0aW9uIDQNCg0KSXRlcmF0aW9uIGluZGV4DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQppIDwtIDQNCmBgYA0KDQojIyMjIFNldHRpbmcgJG0kLCAkbCQgYW5kICRjJA0KDQoqKlNtb290aCB0cmVuZCBmdW5jdGlvbiAkZl8xJCoqDQoNCjEuIFVwZGF0aW5nICRsJCB3aXRoIGl0cyBlc3RpbWF0ZSAkXGhhdHtsfSQgaW4gdGhlIHRoaXJkIGl0ZXJhdGlvbg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mMVtpXSA8LSBsX2YxX2hhdFtpLTFdDQpsX2YxW2ldDQpgYGANCg0KMi4gVGhlIGJvdW5kYXJ5IGZhY3RvciAkYyQgaGFzIHRvIGZ1bGZpbGwgJGMgXCwgXGdlcSBcLCAwLjk3ICsgMS40NSBcLCBcZnJhY3tsfXtTfSQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCjAuOTcgKyAxLjQ1KmxfZjFbaV0vUw0KYGBgDQoNClRoZW4sICRjJCBpcyBzZXQgdG8NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmNfZjFbaV0gPC0gMS41DQpjX2YxW2ldDQpgYGANCg0KMy4gVGhlIG51bWJlciBvZiBiYXNpcyBmdW5jdGlvbnMgJG0kIGFzIGEgZnVuY3Rpb24gb2YgJGwkOiAgJFw7IG09IDEuNzMgXCwgXGZyYWN7Y317KGwvUyleezEuMDV9fSQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmlmKDEuNzMgKiBjX2YxW2ldLyhsX2YxW2ldL1MpXjEuMDUgPCA1KSBtX2YxW2ldIDwtIDUgZWxzZSBtX2YxW2ldIDwtIGNlaWxpbmcoMS43MyAqIGNfZjFbaV0vKGxfZjFbaV0vUyleMS4wNSkNCm1fZjFbaV0NCmBgYA0KDQoqKlllYXJseSBwZXJpb2RpYyBlZmZlY3RzIGZ1bmN0aW9uICRmXzIkKioNCg0KMS4gVXBkYXRpbmcgJGwkIHdpdGggaXRzIGVzdGltYXRlICRcaGF0e2x9JCBpbiB0aGUgdGhpcmQgaXRlcmF0aW9uDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpsX2YyW2ldIDwtIGxfZjJfaGF0W2ktMV0NCmxfZjJbaV0NCmBgYA0KDQoyLiBOdW1iZXIgb2YgYmFzaXMgZnVuY3Rpb25zICRtJCBhcyBhIGZ1bmN0aW9uIG9mICRsJDogICRcOyBtPSAzLjMxIFwsIFxmcmFjezF9e2xeezEuMDV9fSQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmlmKDMuMzEgKiAxL2xfZjJbaV1eMS4wNSA8IDUpIG1fZjJbaV0gPC0gNSBlbHNlIG1fZjJbaV0gPC0gY2VpbGluZygzLjMxICogMS9sX2YyW2ldXjEuMDUpDQptX2YyW2ldDQpgYGANCg0KKipXZWVrbHkgcGVyaW9kaWMgZWZmZWN0cyBmdW5jdGlvbiAkZl8zJCoqDQoNCjEuIFVwZGF0aW5nICRsJCB3aXRoIGl0cyBlc3RpbWF0ZSAkXGhhdHtsfSQgaW4gdGhlIHRoaXJkIGl0ZXJhdGlvbg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mM1tpXSA8LSBsX2YzX2hhdFtpLTFdDQpsX2YzW2ldDQpgYGANCg0KMi4gTnVtYmVyIG9mIGJhc2lzIGZ1bmN0aW9ucyAkbSQgYXMgYSBmdW5jdGlvbiBvZiAkbCQ6ICAkXDsgbT0gMy4zMSBcLCBcZnJhY3sxfXtsXnsxLjA1fX0kDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQppZigzLjMxICogMS9sX2YzW2ldXjEuMDUgPCA1KSBtX2YzW2ldIDwtIDUgZWxzZSBtX2YzW2ldIDwtIGNlaWxpbmcoMy4zMSAqIDEvbF9mM1tpXV4xLjA1KQ0KbV9mM1tpXQ0KYGBgDQoNCiMjIyMgRGF0YSB0byBTdGFuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpzdGFuZGF0YVtbaV1dIDwtIGxpc3QoTV9mMT0gbV9mMVtpXSwgDQogICAgICAgICAgICAgICAgIGNfZjE9IGNfZjFbaV0sIA0KICAgICAgICAgICAgICAgICBKX2YyPSBtX2YyW2ldLCANCiAgICAgICAgICAgICAgICAgSl9mMz0gbV9mM1tpXSwgDQogICAgICAgICAgICAgICAgIHg9IHhbLDFdLCANCiAgICAgICAgICAgICAgICAgeT0geVssMV0sIA0KICAgICAgICAgICAgICAgICBOPSBsZW5ndGgoeCksIA0KICAgICAgICAgICAgICAgICBwZXJpb2RfeWVhcj0gcGVyaW9kX3llYXIsIA0KICAgICAgICAgICAgICAgICBwZXJpb2Rfd2Vlaz0gcGVyaW9kX3dlZWssDQogICAgICAgICAgICAgICAgIGRheV9vZl95ZWFyMj0gZGF5X29mX3llYXIyDQopDQpzdHIoc3RhbmRhdGFbW2ldXSkNCmBgYA0KDQojIyMjIE1vZGVsIGZpdHRpbmcNCg0KQ29tcGlsaW5nIHRoZSBtb2RlbA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPVRSVUUsIGV2YWw9RkFMU0V9DQojIGJpcnRoZGF5X21vZCA8LSBjbWRzdGFucjo6Y21kc3Rhbl9tb2RlbChzdGFuX2ZpbGUgPSAic3RhbmNvZGVfZGVmLnN0YW4iKQ0KYGBgDQoNCk1vZGVsIHNhbXBsaW5nDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGV2YWw9VFJVRX0NCiMgbG9hZCgiZml0LnJEYXRhIikNCmBgYA0KDQpgYGB7ciB3YXJuPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIGV2YWw9RkFMU0V9DQojIGZpdFtbaV1dIDwtIGJpcnRoZGF5X21vZCRzYW1wbGUoZGF0YT0gc3RhbmRhdGFbW2ldXSwgaXRlcl93YXJtdXA9MjAwLCBpdGVyX3NhbXBsaW5nPTIwMCwgY2hhaW5zPTQsIHRoaW49NCwgaW5pdD0wLjUsIGFkYXB0X2RlbHRhPTAuOSwgc2F2ZV93YXJtdXA9RkFMU0UpDQojIGZpdFtbaV1dIDwtIHJzdGFuOjpyZWFkX3N0YW5fY3N2KGZpdFtbaV1dJG91dHB1dF9maWxlcygpKQ0KDQojIHNhdmUoZml0LCBmaWxlPSJmaXQuckRhdGEiKQ0KYGBgDQoNClN1bW1hcmllcyBvZiB2YXJpYWJsZSBlc3RpbWF0ZXMNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZXZhbD1UUlVFfQ0KcGFyYW0gPSBjKCJpbnRlcmNlcHQiLCJsc2NhbGVbMV0iLCJsc2NhbGVbMl0iLCJsc2NhbGVbM10iLCJncHNjYWxlWzFdIiwiZ3BzY2FsZVsyXSIsImdwc2NhbGVbM10iLCJub2lzZSIsInNpZ21hX2Y0IikNCnN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBwYXJhbSwgcHJvYnMgPSBjKDAuMDI1LCAwLjUsIDAuOTc1KSwgZGlnaXRzX3N1bW1hcnkgPSA0KSRzdW1tYXJ5DQpgYGANCg0KU2ltdWxhdGlvbiBjaGFpbnMgZm9yIHRoZSB2YXJpYWJsZXMgYWZ0ZXIgd2FybXVwDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTE1LCBldmFsPVRSVUV9DQp0cmFjZXBsb3QoZml0W1tpXV0sIHBhcnMgPSBwYXJhbSwgaW5jbHVkZSA9IFRSVUUsIHVuY29uc3RyYWluID0gRkFMU0UsIGluY193YXJtdXAgPSBGQUxTRSwgd2luZG93ID0gTlVMTCwgbnJvdyA9IE5VTEwsIG5jb2wgPSBOVUxMKQ0KYGBgDQoNClBsb3Qgb2YgdGhlIG1lYW4gcG9zdGVyaW9yIGZ1bmN0aW9uICRmXzEkDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTE1LCBmaWcuYWxpZ249J2NlbnRlcicsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCmYgPC0gc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IGMoImYiKSwgcHJvYnMgPSBjKDAuMDI1LCAwLjUsIDAuOTc1KSkkc3VtbWFyeQ0KaW50ZXJjZXB0IDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJpbnRlcmNlcHQiKSwgcHJvYnMgPSBjKDAuMDI1LCAwLjUsIDAuOTc1KSkkc3VtbWFyeQ0KZjEgPC0gc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IGMoImYxIiksIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSkpJHN1bW1hcnkNCmYyIDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJmMiIpLCBwcm9icyA9IGMoMC4wMjUsIDAuNSwgMC45NzUpKSRzdW1tYXJ5DQpmMyA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygiZjMiKSwgcHJvYnMgPSBjKDAuMDI1LCAwLjUsIDAuOTc1KSkkc3VtbWFyeQ0KZjQgPC0gc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IGMoImY0IiksIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSkpJHN1bW1hcnkNCmBgYA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xNSwgZmlnLmFsaWduPSdjZW50ZXInLCBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQpwYXIobWFpPWMoMSwgMC44MiwgMC4xLCAwLjQyKSkNCg0KaW5kIDwtIGRhdGEkaWQNCmxhYmVsc19hdCA9IGFnZ3JlZ2F0ZShkYXRhLCBieT1saXN0KGRhdGEkeWVhciksIEZVTj1taW4pJGlkDQoNCm9ic19wbHQgPC0gKCh5W2luZF0taW50ZXJjZXB0WzFdLWYyW2luZCwxXS1mM1tpbmQsMV0tZjRbZGF0YSRkYXlfb2ZfeWVhcjIsMV1baW5kXSkqc3RkX3krbV95KS9tX3kNCnBsb3QoaW5kLCBvYnNfcGx0LCB0eXBlPSJwIiwgcGNoPTIwLCBiZz1ncmV5KDAuNCksIGNleD0wLjYsIGNvbD1ncmV5KDAuNSksIHhsYWI9IiIsIHlsYWI9IiIsIGx3ZD0xLCB5bGltPWMoMC44LDEuMiksIG1ncD1jKDMuNSwgMSwgMCksIGZyYW1lLnBsb3Q9VFJVRSwgeWF4cz0iciIsIGNleC5heGlzPTEuNiwgY2V4LmxhYj0xLjYsIGxhcz0xLCB4YXh0PSJuIiwgeWF4dD0ibiIsIGZnPWdyZXkoMC41KSwgZmFtaWx5PSJzZXJpZiIpDQoNCmF4aXMoMSwgYXQ9bGFiZWxzX2F0LCBjKCIxOTY5IiwiMTk3MCIsIjE5NzEiLCIxOTcyIiwiMTk3MyIsIjE5NzQiLCIxOTc1IiwiMTk3NiIsIjE5NzciLCIxOTc4IiwiMTk3OSIsIjE5ODAiLCIxOTgxIiwiMTk4MiIsIjE5ODMiLCIxOTg0IiwiMTk4NSIsIjE5ODYiLCIxOTg3IiwiMTk4OCIpLCB0aWNrPVRSVUUsIGx0eT0xLCBtZ3A9YygzLCAxLCAwKSwgbGFzPTEsIGNleC5heGlzPTEuNiwgZm9udD0xLCBjb2w9Z3JleSgwLjUpLCBjb2wudGlja3M9Z3JleSgwLjMpLCBmYW1pbHk9IiIpDQpheGlzKDIsIGF0PU5VTEwsIGxhYmVscz1UUlVFLCB0aWNrPVRSVUUsIGx0eT0xLCBtZ3A9YygzLCAwLjcsIDApLCBsYXM9MSwgY2V4LmF4aXM9MS42LCBmb250PTUsIGNvbD1ncmV5KDAuNSksIGNvbC50aWNrcz1ncmV5KDAuMykpDQp0aXRsZSh4bGFiPSJZZWFyIiwgbWdwPWMoMywgMSwgMCksIGNleC5sYWI9MS42LCBsYXM9MSkNCnRpdGxlKHlsYWI9IlByb3BvcnRpb24gb2YgYmlydGhzIG92ZXIgdGhlIG1lYW4iLCBtZ3A9YygzLCAwLjcsIDApLCBjZXgubGFiPTEuNiwgbGFzPTEpDQoNCmFibGluZShoPTEsIGx0eT0yKQkJCQkJCQkJCQkJCSAgICAgICAgICAgICAgICAjIG1lYW4NCmxpbmVzKGluZCwgKGYxW2luZCwxXSpzdGRfeSttX3kpL21feSwgY29sPTIsIGx3ZD0yKQkJCQkjIGYxDQoNCmxlZ2VuZCgidG9wbGVmdCIsIGluc2V0PWMoMC4yMiwwLjAyKSwgbGVnZW5kPWMoVGVYKCdPYnNlcnZhdGlvbnMgLSBpbnRlcmNlcHQgLSAkZl8yJCAtICRmXzMkIC0gJGZfNCQnKSxUZVgoJyRmXzEkJykpLCBjb2w9YyhncmV5KDAuNCksMiwzLCJncmV5IiksIGx0eT1jKE5BLDEsMSwxKSwgcGNoPWMoMjAsTkEsTkEsTkEpLCBsd2Q9YygxLDMsMywzKSwgY2V4PTEuNCwgeHBkPVRSVUUsIGJ0eT0ibiIsIHkuaW50ZXJzcD0xLCB4LmludGVyc3A9MC44LCB0ZXh0LmZvbnQ9MSwgbmNvbD0xLCBzZWcubGVuPTEuNSkNCmBgYA0KDQpQbG90IG9mIHRoZSBtZWFuIHBvc3RlcmlvciBmdW5jdGlvbiAkZl8yJA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xNSwgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KcGFyKG1haT1jKDEsIDAuODIsIDAuMSwgMC40MikpDQoNCmRhdGFfeWVhciA8LSBkYXRhW2RhdGEkeWVhciAlaW4lIHNlcSgxOTY5LDE5ODEsMSksXQ0KaW5kIDwtIGRhdGFfeWVhciRpZA0KYXhpc19sYWJlbHNfYXQgPC0gYWdncmVnYXRlKGRhdGFfeWVhciwgYnk9bGlzdChkYXRhX3llYXIkeWVhciksIEZVTj1taW4pJGlkDQoNCm9icyA8LSAoKHlbaW5kXS1pbnRlcmNlcHRbMV0tZjFbaW5kLDFdLWYzW2luZCwxXS1mNFtkYXRhJGRheV9vZl95ZWFyMiwxXVtpbmRdKSpzdGRfeSttX3kpL21feQ0KcGxvdChpbmQsIG9icywgdHlwZT0icCIsIGx0eT0xLCBwY2g9MjAsIGNleD0wLjYsIGNvbD1ncmV5KDAuNSksIHhsYWI9IiIsIHlsYWI9IlByb3BvcnRpb24gb2YgYmlydGhzIG92ZXIgdGhlIG1lYW4iLCBjZXgubGFiPTEuNSwgY2V4LmF4aXM9MS42LCB4YXh0PSJuIiwgeWxpbT1jKDAuODUsMS4xNSkpDQoNCmF4aXMoMSwgYXQ9YXhpc19sYWJlbHNfYXQsIGxhYmVscz1hcy5jaGFyYWN0ZXIoc2VxKDE5NjksMTk4MSwxKSksIHRpY2s9VFJVRSwgY2V4LmF4aXM9MS42KQ0KDQpsaW5lcyhyYW5nZShpbmQpLCBjKDEsMSksIGx0eT0yLCBsd2Q9MSkJCQkJCQkgICAgICAgICMgbWVhbg0KbGluZXMoaW5kLCAoZjJbaW5kLDFdKnN0ZF95K21feSkvbV95LCBjb2w9MywgbHdkPTIpCSAJCSAgIyBmMg0KDQphYmxpbmUodj1heGlzX2xhYmVsc19hdCwgbHR5PTIsIGNvbD1ncmV5KDAuNykpDQpsZWdlbmQoInRvcGxlZnQiLCBpbnNldD1jKDAuMDUsMC4wMDUpLCBsZWdlbmQ9YyhUZVgoJ09ic2VydmF0aW9ucyAtIGludGVyY2VwdCAtICRmXzEkIC0gJGZfMyQgLSAkZl80JCcpLFRlWCgnJGZfMiQnKSksIGNvbD1jKGdyZXkoMC41KSwzKSwgbHR5PWMoTkEsMSksIHBjaD1jKDIwLE5BKSwgbHdkPWMoMywzKSwgY2V4PTEuNCwgeHBkPVRSVUUsIGJ0eT0ibiIsIHkuaW50ZXJzcD0xLCB4LmludGVyc3A9MC44LCB0ZXh0LmZvbnQ9MSwgbmNvbD0xLCBzZWcubGVuPTEuMykNCmBgYA0KDQpQbG90IG9mIHRoZSBtZWFuIHBvc3RlcmlvciBmdW5jdGlvbiAkZl8xICsgZl8yJA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xNSwgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KcGFyKG1haT1jKDEsIDAuODIsIDAuMSwgMC40MikpDQoNCmRhdGFfeWVhciA8LSBkYXRhW2RhdGEkeWVhciAlaW4lIHNlcSgxOTY5LDE5ODEsMSksXQ0KaW5kIDwtIGRhdGFfeWVhciRpZA0KYXhpc19sYWJlbHNfYXQgPC0gYWdncmVnYXRlKGRhdGFfeWVhciwgYnk9bGlzdChkYXRhX3llYXIkeWVhciksIEZVTj1taW4pJGlkDQoNCm9icyA8LSAoKHlbaW5kXS1pbnRlcmNlcHRbMV0tZjNbaW5kLDFdLWY0W2RhdGEkZGF5X29mX3llYXIyLDFdW2luZF0pKnN0ZF95K21feSkvbV95DQpwbG90KGluZCwgb2JzLCB0eXBlPSJwIiwgbHR5PTEsIHBjaD0yMCwgY2V4PTAuNiwgY29sPWdyZXkoMC41KSwgeGxhYj0iIiwgeWxhYj0iUHJvcG9ydGlvbiBvZiBiaXJ0aHMgb3ZlciB0aGUgbWVhbiIsIGNleC5sYWI9MS41LCBjZXguYXhpcz0xLjYsIHhheHQ9Im4iLCB5bGltPWMoMC44LDEuMikpDQoNCmF4aXMoMSwgYXQ9YXhpc19sYWJlbHNfYXQsIGxhYmVscz1hcy5jaGFyYWN0ZXIoc2VxKDE5NjksMTk4MSwxKSksIHRpY2s9VFJVRSwgY2V4LmF4aXM9MS42KQ0KDQpsaW5lcyhyYW5nZShpbmQpLCBjKDEsMSksIGx0eT0yLCBsd2Q9MSkJCQkJCQkgICAgICAgICAgICAgICAgICAgICMgbWVhbg0KbGluZXMoaW5kLCAoKGYxW2luZCwxXStmMltpbmQsMV0pKnN0ZF95K21feSkvbV95LCBjb2w9NCwgbHdkPTIpCSAJCSAgIyBmMSArIGYyDQoNCmFibGluZSh2PWF4aXNfbGFiZWxzX2F0LCBsdHk9MiwgY29sPWdyZXkoMC43KSkNCmxlZ2VuZCgidG9wbGVmdCIsIGluc2V0PWMoMC4wNSwwLjAwNSksIGxlZ2VuZD1jKFRlWCgnT2JzZXJ2YXRpb25zIC0gaW50ZXJjZXB0IC0gJGZfMyQgLSAkZl80JCcpLFRlWCgnJGZfMSArIGZfMiQnKSksIGNvbD1jKGdyZXkoMC41KSw0KSwgbHR5PWMoTkEsMSksIHBjaD1jKDIwLE5BKSwgbHdkPWMoMywzKSwgY2V4PTEuNCwgeHBkPVRSVUUsIGJ0eT0ibiIsIHkuaW50ZXJzcD0xLCB4LmludGVyc3A9MC44LCB0ZXh0LmZvbnQ9MSwgbmNvbD0xLCBzZWcubGVuPTEuMykNCmBgYA0KDQpQbG90IG9mIHRoZSByZXNpZHVhbHMNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTUsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCnBhcihtYWk9YygxLCAwLjgyLCAwLjEsIDAuNDIpKQ0KDQpkYXRhX3llYXIgPC0gZGF0YVtkYXRhJHllYXIgJWluJSBzZXEoMTk2OSwxOTgxLDEpLF0NCmluZCA8LSBkYXRhX3llYXIkaWQNCmF4aXNfbGFiZWxzX2F0IDwtIGFnZ3JlZ2F0ZShkYXRhX3llYXIsIGJ5PWxpc3QoZGF0YV95ZWFyJHllYXIpLCBGVU49bWluKSRpZA0KDQpvYnMgPC0gKCh5W2luZF0taW50ZXJjZXB0WzFdLWYxW2luZCwxXS1mMltpbmQsMV0tZjNbaW5kLDFdLWY0W2RhdGEkZGF5X29mX3llYXIyLDFdW2luZF0pKnN0ZF95K21feSkvbV95DQpwbG90KGluZCwgb2JzLCB0eXBlPSJwIiwgbHR5PTEsIHBjaD0yMCwgY2V4PTAuNiwgY29sPWdyZXkoMC41KSwgeGxhYj0iIiwgeWxhYj0iUHJvcG9ydGlvbiBvZiBiaXJ0aHMgb3ZlciB0aGUgbWVhbiIsIGNleC5sYWI9MS41LCBjZXguYXhpcz0xLjYsIHhheHQ9Im4iLCB5bGltPWMoMC44LDEuMikpDQoNCmF4aXMoMSwgYXQ9YXhpc19sYWJlbHNfYXQsIGxhYmVscz1hcy5jaGFyYWN0ZXIoc2VxKDE5NjksMTk4MSwxKSksIHRpY2s9VFJVRSwgY2V4LmF4aXM9MS42KQ0KDQpsaW5lcyhyYW5nZShpbmQpLCBjKDEsMSksIGx0eT0yLCBsd2Q9MSkJCQkJCQkgICAgICAgICAgICAgICAgICAgICMgbWVhbg0KDQphYmxpbmUodj1heGlzX2xhYmVsc19hdCwgbHR5PTIsIGNvbD1ncmV5KDAuNykpDQpsZWdlbmQoInRvcGxlZnQiLCBpbnNldD1jKDAuMDUsMC4wMDUpLCBsZWdlbmQ9YyhUZVgoJ09ic2VydmF0aW9ucyAtIGludGVyY2VwdCAtICRmXzEkIC0gJGZfMiQgLSAkZl8zJCAtICRmXzQkJykpLCBjb2w9YyhncmV5KDAuNSksNCksIGx0eT1jKE5BLDEpLCBwY2g9YygyMCxOQSksIGx3ZD1jKDMsMyksIGNleD0xLjQsIHhwZD1UUlVFLCBidHk9Im4iLCB5LmludGVyc3A9MSwgeC5pbnRlcnNwPTAuOCwgdGV4dC5mb250PTEsIG5jb2w9MSwgc2VnLmxlbj0xLjMpDQpgYGANCg0KIyMjIyBNb2RlbCBldmFsdWF0aW9uDQoNClJlc2lkdWFscw0KDQpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD00LCBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KZiA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygiZiIpKSRzdW1tYXJ5WywxXQ0KcmVzW1tpXV0gPC0gc3RhbmRhdGFbW2ldXSR5IC0gZg0KDQpnZ3Bsb3QoYXMuZGF0YS5mcmFtZShyZXNbW2ldXSksIGFlcyhyZXNbW2ldXSkpICArDQogIGdlb21faGlzdG9ncmFtKGNvbG9yID0gJ3doaXRlJykgKw0KICB0aGVtZV9jbGFzc2ljKCkNCmBgYA0KDQpSb290IG1lYW4gc3F1YXJlZCBlcnJvcg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0Kcm1zZVtpXSA8LSBzcXJ0KG1lYW4ocmVzW1tpXV1eMikpDQpybXNlW2ldDQpgYGANCg0KQmF5ZXNpYW4gJFJeMiQgKENvZWZmaWNpZW50IG9mIGRldGVybWluYXRpb24pDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTQsIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpub2lzZSA8LSBhcy5tYXRyaXgoZml0W1tpXV0sIHBhcnMgPSBjKCJub2lzZSIpKQ0Kc2RfZiA8LSBhcHBseShhcy5tYXRyaXgoZml0W1tpXV0sIHBhcnMgPSBjKCJmIikpLCAxLCBzZCkNClIyIDwtIHNkX2ZeMi8oc2RfZl4yICsgbm9pc2VeMikNCg0KZ2dwbG90KGFzLmRhdGEuZnJhbWUoUjIpLCBhZXMoUjIpKSAgKw0KICBnZW9tX2hpc3RvZ3JhbShjb2xvciA9ICd3aGl0ZScpICsNCiAgdGhlbWVfY2xhc3NpYygpDQpgYGANCg0KTWVkaWFuIG9mICRSXjIkDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTQsIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQplUjJbaV0gPC0gbWVkaWFuKFIyKQ0KZVIyW2ldDQpgYGANCg0KTG9nIHByZWRpY3RpdmUgZGVuc2l0eSAobHBkKQ0KDQpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD00LCBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbHBkIDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJsb2dfbGlrIikpJHN1bW1hcnlbLDFdDQoNCmdncGxvdChhcy5kYXRhLmZyYW1lKGxwZCksIGFlcyhscGQpKSAgKw0KICBnZW9tX2hpc3RvZ3JhbShjb2xvciA9ICd3aGl0ZScpICsNCiAgdGhlbWVfY2xhc3NpYygpDQpgYGANCg0KTWVkaWFuIG9mIGxwZA0KDQpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD00LCBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KZWxwZFtpXSA8LSBtZWRpYW4obHBkKQ0KZWxwZFtpXQ0KYGBgDQoNCiMjIyMgRGlhZ25vc2lzDQoNCioqU21vb3RoIHRyZW5kIGZ1bmN0aW9uICRmXzEkKioNCg0KMS4gRXN0aW1hdGVkIGxlbmd0aHNjYWxlICRcaGF0e2x9JCAgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpsX2YxX2hhdFtpXSA8LSByb3VuZChzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gImxzY2FsZVsxXSIpJHN1bW1hcnlbLDFdLCAyKQ0KbF9mMV9oYXRbaV0NCmBgYA0KDQoyLiBDaGVjayB3aGV0aGVyICRcaGF0e2x9JCBpcyBlcXVhbCB0byBvciBncmVhdGVyIHRoYW4gYGxfZjFgICh0aGUgbWluaW11bSAkbCQgdGhhdCBjYW4gYmUgYWNjdXJhdGVseSBmaXR0ZWQgZGV0ZXJtaW5lZCBieSB0aGUgJG0kIHVzZWQpDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpsX2YxX2hhdFtpXSA+PSBsX2YxW2ldDQpgYGANCg0KKipZZWFybHkgcGVyaW9kaWMgZWZmZWN0cyBmdW5jdGlvbiAkZl8yJCoqDQoNCjEuIEVzdGltYXRlZCBsZW5ndGhzY2FsZSAkXGhhdHtsfSQgIA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mMl9oYXRbaV0gPC0gcm91bmQoc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9ICJsc2NhbGVbMl0iKSRzdW1tYXJ5WywxXSwgMikNCmxfZjJfaGF0W2ldDQpgYGANCg0KMi4gQ2hlY2sgd2hldGhlciAkXGhhdHtsfSQgaXMgZXF1YWwgdG8gb3IgZ3JlYXRlciB0aGFuIGBsX2YyYCAodGhlIG1pbmltdW0gJGwkIHRoYXQgY2FuIGJlIGFjY3VyYXRlbHkgZml0dGVkIGRldGVybWluZWQgYnkgdGhlICRtJCB1c2VkKQ0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mMl9oYXRbaV0gPj0gbF9mMltpXQ0KYGBgDQoNCioqV2Vla2x5IHBlcmlvZGljIGVmZmVjdHMgZnVuY3Rpb24gJGZfMyQqKg0KDQoxLiBFc3RpbWF0ZWQgbGVuZ3Roc2NhbGUgJFxoYXR7bH0kICANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjNfaGF0W2ldIDwtIHJvdW5kKHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSAibHNjYWxlWzNdIikkc3VtbWFyeVssMV0sIDIpDQpsX2YzX2hhdFtpXQ0KYGBgDQoNCjIuIENoZWNrIHdoZXRoZXIgJFxoYXR7bH0kIGlzIGVxdWFsIHRvIG9yIGdyZWF0ZXIgdGhhbiBgbF9mM2AgKHRoZSBtaW5pbXVtICRsJCB0aGF0IGNhbiBiZSBhY2N1cmF0ZWx5IGZpdHRlZCBkZXRlcm1pbmVkIGJ5IHRoZSAkbSQgdXNlZCkNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjNfaGF0W2ldID49IGxfZjNbaV0NCmBgYA0KDQoqKlN1bW1hcnkgdGFibGUqKg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD01LCBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBlY2hvPUZBTFNFfQ0KZGlhZ25vc2lzW1tpXV0gPC0gZGF0YS5mcmFtZShpdGVyPSByZXAoaSwzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdQX2Z1bmM9IGMoImYxIiwiZjIiLCJmMyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbD0gcm91bmQoYyhsX2YxW2ldLGxfZjJbaV0sbF9mM1tpXSksMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjPSByb3VuZChjKGNfZjFbaV0sTkEsTkEpLDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbT0gYyhtX2YxW2ldLG1fZjJbaV0sbV9mM1tpXSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsX2hhdD0gcm91bmQoYyhsX2YxX2hhdFtpXSxsX2YyX2hhdFtpXSxsX2YzX2hhdFtpXSksMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnbF9oYXQgPiBsJyA9IGMobF9mMV9oYXRbaV0gPj0gbF9mMVtpXSxsX2YyX2hhdFtpXSA+PSBsX2YyW2ldLGxfZjNfaGF0W2ldID49IGxfZjNbaV0pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnNtZSA9IHJvdW5kKHJlcChybXNlW2ldLDMpLDMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUjIgPSByb3VuZChyZXAoZVIyW2ldLDMpLDMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxwZCA9IHJvdW5kKHJlcChlbHBkW2ldLDMpLDMpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApDQpuYW1lcyhkaWFnbm9zaXNbW2ldXSkgPC0gYygiaXRlciIsICJHUF9mdW5jIiwgImwiLCAiYyIsICJtIiwgImxfaGF0IiwgImxfaGF0ID4gbCIsICJybXNlIiwgIlIyIiwgImVscGQiKQ0KZGlhZ25vc2lzW1tpXV0NCmBgYA0KDQoNCiMjIyBJdGVyYXRpb24gNQ0KDQpJdGVyYXRpb24gaW5kZXgNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmkgPC0gNQ0KYGBgDQoNCiMjIyMgU2V0dGluZyAkbSQsICRsJCBhbmQgJGMkDQoNCioqU21vb3RoIHRyZW5kIGZ1bmN0aW9uICRmXzEkKioNCg0KMS4gVXBkYXRpbmcgJGwkIHdpdGggaXRzIGVzdGltYXRlICRcaGF0e2x9JCBpbiB0aGUgZm91cnRoIGl0ZXJhdGlvbg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mMVtpXSA8LSBsX2YxX2hhdFtpLTFdDQpsX2YxW2ldDQpgYGANCg0KMi4gVGhlIGJvdW5kYXJ5IGZhY3RvciAkYyQgaGFzIHRvIGZ1bGZpbGwgJGMgXCwgXGdlcSBcLCAwLjk3ICsgMS40NSBcLCBcZnJhY3tsfXtTfSQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCjAuOTcgKyAxLjQ1KmxfZjFbaV0vUw0KYGBgDQoNClRoZW4sICRjJCBpcyBzZXQgdG8NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmNfZjFbaV0gPC0gMS41DQpjX2YxW2ldDQpgYGANCg0KMy4gVGhlIG51bWJlciBvZiBiYXNpcyBmdW5jdGlvbnMgJG0kIGFzIGEgZnVuY3Rpb24gb2YgJGwkOiAgJFw7IG09IDEuNzMgXCwgXGZyYWN7Y317KGwvUyleezEuMDV9fSQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmlmKDEuNzMgKiBjX2YxW2ldLyhsX2YxW2ldL1MpXjEuMDUgPCA1KSBtX2YxW2ldIDwtIDUgZWxzZSBtX2YxW2ldIDwtIGNlaWxpbmcoMS43MyAqIGNfZjFbaV0vKGxfZjFbaV0vUyleMS4wNSkNCg0KbV9mMVtpXQ0KYGBgDQoNCioqWWVhcmx5IHBlcmlvZGljIGVmZmVjdHMgZnVuY3Rpb24gJGZfMiQqKg0KDQoxLiBVcGRhdGluZyAkbCQgd2l0aCBpdHMgZXN0aW1hdGUgJFxoYXR7bH0kIGluIHRoZSB0aGlyZCBpdGVyYXRpb24NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjJbaV0gPC0gbF9mMl9oYXRbaS0xXQ0KbF9mMltpXQ0KYGBgDQoNCjIuIE51bWJlciBvZiBiYXNpcyBmdW5jdGlvbnMgJG0kIGFzIGEgZnVuY3Rpb24gb2YgJGwkOiAgJFw7IG09IDMuMzEgXCwgXGZyYWN7MX17bF57MS4wNX19JA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KaWYoMy4zMSAqIDEvbF9mMltpXV4xLjA1IDwgNSkgbV9mMltpXSA8LSA1IGVsc2UgbV9mMltpXSA8LSBjZWlsaW5nKDMuMzEgKiAxL2xfZjJbaV1eMS4wNSk7DQptX2YyW2ldDQpgYGANCg0KKipXZWVrbHkgcGVyaW9kaWMgZWZmZWN0cyBmdW5jdGlvbiAkZl8zJCoqDQoNCjEuIFVwZGF0aW5nICRsJCB3aXRoIGl0cyBlc3RpbWF0ZSAkXGhhdHtsfSQgaW4gdGhlIGZvdXJ0aCBpdGVyYXRpb24NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjNbaV0gPC0gbF9mM19oYXRbaS0xXQ0KbF9mM1tpXQ0KYGBgDQoNCjIuIE51bWJlciBvZiBiYXNpcyBmdW5jdGlvbnMgJG0kIGFzIGEgZnVuY3Rpb24gb2YgJGwkOiAgJFwsIG09IDMuMzEgXCwgXGZyYWN7MX17bF57MS4wNX19JA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KaWYoMy4zMSAqIDEvbF9mM1tpXV4xLjA1IDwgNSkgbV9mM1tpXSA8LSA1IGVsc2UgbV9mM1tpXSA8LSBjZWlsaW5nKDMuMzEgKiAxL2xfZjNbaV1eMS4wNSkNCm1fZjNbaV0NCmBgYA0KDQojIyMjIERhdGEgdG8gU3Rhbg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0Kc3RhbmRhdGFbW2ldXSA8LSBsaXN0KE1fZjE9IG1fZjFbaV0sIA0KICAgICAgICAgICAgICAgICBjX2YxPSBjX2YxW2ldLCANCiAgICAgICAgICAgICAgICAgSl9mMj0gbV9mMltpXSwgDQogICAgICAgICAgICAgICAgIEpfZjM9IG1fZjNbaV0sIA0KICAgICAgICAgICAgICAgICB4PSB4WywxXSwgDQogICAgICAgICAgICAgICAgIHk9IHlbLDFdLCANCiAgICAgICAgICAgICAgICAgTj0gbGVuZ3RoKHgpLCANCiAgICAgICAgICAgICAgICAgcGVyaW9kX3llYXI9IHBlcmlvZF95ZWFyLCANCiAgICAgICAgICAgICAgICAgcGVyaW9kX3dlZWs9IHBlcmlvZF93ZWVrLA0KICAgICAgICAgICAgICAgICBkYXlfb2ZfeWVhcjI9IGRheV9vZl95ZWFyMg0KKQ0Kc3RyKHN0YW5kYXRhW1tpXV0pDQpgYGANCg0KIyMjIyBNb2RlbCBmaXR0aW5nDQoNCkNvbXBpbGluZyB0aGUgbW9kZWwNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1UUlVFLCBldmFsPUZBTFNFfQ0KIyBiaXJ0aGRheV9tb2QgPC0gY21kc3RhbnI6OmNtZHN0YW5fbW9kZWwoc3Rhbl9maWxlID0gInN0YW5jb2RlX2RlZi5zdGFuIikNCmBgYA0KDQpNb2RlbCBzYW1wbGluZw0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBldmFsPVRSVUV9DQojIGxvYWQoImZpdC5yRGF0YSIpDQpgYGANCg0KYGBge3Igd2Fybj1UUlVFLCBtZXNzYWdlPUZBTFNFLCBldmFsPUZBTFNFfQ0KIyBmaXRbW2ldXSA8LSBiaXJ0aGRheV9tb2Qkc2FtcGxlKGRhdGE9IHN0YW5kYXRhW1tpXV0sIGl0ZXJfd2FybXVwPTIwMCwgaXRlcl9zYW1wbGluZz0yMDAsIGNoYWlucz00LCB0aGluPTQsIGluaXQ9MC41LCBhZGFwdF9kZWx0YT0wLjksIHNhdmVfd2FybXVwPUZBTFNFKQ0KIyBmaXRbW2ldXSA8LSByc3Rhbjo6cmVhZF9zdGFuX2NzdihmaXRbW2ldXSRvdXRwdXRfZmlsZXMoKSkNCg0KIyBzYXZlKGZpdCwgZmlsZT0iZml0LnJEYXRhIikNCmBgYA0KDQpTdW1tYXJpZXMgb2YgdmFyaWFibGUgZXN0aW1hdGVzDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGV2YWw9VFJVRX0NCnBhcmFtID0gYygiaW50ZXJjZXB0IiwibHNjYWxlWzFdIiwibHNjYWxlWzJdIiwibHNjYWxlWzNdIiwiZ3BzY2FsZVsxXSIsImdwc2NhbGVbMl0iLCJncHNjYWxlWzNdIiwibm9pc2UiLCJzaWdtYV9mNCIpDQpzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gcGFyYW0sIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSksIGRpZ2l0c19zdW1tYXJ5ID0gNCkkc3VtbWFyeQ0KYGBgDQoNClNpbXVsYXRpb24gY2hhaW5zIGZvciB0aGUgdmFyaWFibGVzIGFmdGVyIHdhcm11cA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xNSwgZXZhbD1UUlVFfQ0KdHJhY2VwbG90KGZpdFtbaV1dLCBwYXJzID0gcGFyYW0sIGluY2x1ZGUgPSBUUlVFLCB1bmNvbnN0cmFpbiA9IEZBTFNFLCBpbmNfd2FybXVwID0gRkFMU0UsIHdpbmRvdyA9IE5VTEwsIG5yb3cgPSBOVUxMLCBuY29sID0gTlVMTCkNCmBgYA0KDQpQbG90IG9mIHRoZSBtZWFuIHBvc3RlcmlvciBmdW5jdGlvbiAkZl8xJA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xNSwgZmlnLmFsaWduPSdjZW50ZXInLCBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQpmIDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJmIiksIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSkpJHN1bW1hcnkNCmludGVyY2VwdCA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygiaW50ZXJjZXB0IiksIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSkpJHN1bW1hcnkNCmYxIDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJmMSIpLCBwcm9icyA9IGMoMC4wMjUsIDAuNSwgMC45NzUpKSRzdW1tYXJ5DQpmMiA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygiZjIiKSwgcHJvYnMgPSBjKDAuMDI1LCAwLjUsIDAuOTc1KSkkc3VtbWFyeQ0KZjMgPC0gc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IGMoImYzIiksIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSkpJHN1bW1hcnkNCmY0IDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJmNCIpLCBwcm9icyA9IGMoMC4wMjUsIDAuNSwgMC45NzUpKSRzdW1tYXJ5DQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTUsIGZpZy5hbGlnbj0nY2VudGVyJywgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KcGFyKG1haT1jKDEsIDAuODIsIDAuMSwgMC40MikpDQoNCmluZCA8LSBkYXRhJGlkDQpsYWJlbHNfYXQgPSBhZ2dyZWdhdGUoZGF0YSwgYnk9bGlzdChkYXRhJHllYXIpLCBGVU49bWluKSRpZA0KDQpvYnNfcGx0IDwtICgoeVtpbmRdLWludGVyY2VwdFsxXS1mMltpbmQsMV0tZjNbaW5kLDFdLWY0W2RhdGEkZGF5X29mX3llYXIyLDFdW2luZF0pKnN0ZF95K21feSkvbV95DQpwbG90KGluZCwgb2JzX3BsdCwgdHlwZT0icCIsIHBjaD0yMCwgYmc9Z3JleSgwLjQpLCBjZXg9MC42LCBjb2w9Z3JleSgwLjUpLCB4bGFiPSIiLCB5bGFiPSIiLCBsd2Q9MSwgeWxpbT1jKDAuOCwxLjIpLCBtZ3A9YygzLjUsIDEsIDApLCBmcmFtZS5wbG90PVRSVUUsIHlheHM9InIiLCBjZXguYXhpcz0xLjYsIGNleC5sYWI9MS42LCBsYXM9MSwgeGF4dD0ibiIsIHlheHQ9Im4iLCBmZz1ncmV5KDAuNSksIGZhbWlseT0ic2VyaWYiKQ0KDQpheGlzKDEsIGF0PWxhYmVsc19hdCwgYygiMTk2OSIsIjE5NzAiLCIxOTcxIiwiMTk3MiIsIjE5NzMiLCIxOTc0IiwiMTk3NSIsIjE5NzYiLCIxOTc3IiwiMTk3OCIsIjE5NzkiLCIxOTgwIiwiMTk4MSIsIjE5ODIiLCIxOTgzIiwiMTk4NCIsIjE5ODUiLCIxOTg2IiwiMTk4NyIsIjE5ODgiKSwgdGljaz1UUlVFLCBsdHk9MSwgbWdwPWMoMywgMSwgMCksIGxhcz0xLCBjZXguYXhpcz0xLjYsIGZvbnQ9MSwgY29sPWdyZXkoMC41KSwgY29sLnRpY2tzPWdyZXkoMC4zKSwgZmFtaWx5PSIiKQ0KYXhpcygyLCBhdD1OVUxMLCBsYWJlbHM9VFJVRSwgdGljaz1UUlVFLCBsdHk9MSwgbWdwPWMoMywgMC43LCAwKSwgbGFzPTEsIGNleC5heGlzPTEuNiwgZm9udD01LCBjb2w9Z3JleSgwLjUpLCBjb2wudGlja3M9Z3JleSgwLjMpKQ0KdGl0bGUoeGxhYj0iWWVhciIsIG1ncD1jKDMsIDEsIDApLCBjZXgubGFiPTEuNiwgbGFzPTEpDQp0aXRsZSh5bGFiPSJQcm9wb3J0aW9uIG9mIGJpcnRocyBvdmVyIHRoZSBtZWFuIiwgbWdwPWMoMywgMC43LCAwKSwgY2V4LmxhYj0xLjYsIGxhcz0xKQ0KDQphYmxpbmUoaD0xLCBsdHk9MikJCQkJCQkJCQkJCQkgICAgICAgICAgICAgICAgIyBtZWFuDQpsaW5lcyhpbmQsIChmMVtpbmQsMV0qc3RkX3krbV95KS9tX3ksIGNvbD0yLCBsd2Q9MikJCQkJIyBmMQ0KDQpsZWdlbmQoInRvcGxlZnQiLCBpbnNldD1jKDAuMjIsMC4wMiksIGxlZ2VuZD1jKFRlWCgnT2JzZXJ2YXRpb25zIC0gaW50ZXJjZXB0IC0gJGZfMiQgLSAkZl8zJCAtICRmXzQkJyksVGVYKCckZl8xJCcpKSwgY29sPWMoZ3JleSgwLjQpLDIsMywiZ3JleSIpLCBsdHk9YyhOQSwxLDEsMSksIHBjaD1jKDIwLE5BLE5BLE5BKSwgbHdkPWMoMSwzLDMsMyksIGNleD0xLjQsIHhwZD1UUlVFLCBidHk9Im4iLCB5LmludGVyc3A9MSwgeC5pbnRlcnNwPTAuOCwgdGV4dC5mb250PTEsIG5jb2w9MSwgc2VnLmxlbj0xLjUpDQpgYGANCg0KUGxvdCBvZiB0aGUgbWVhbiBwb3N0ZXJpb3IgZnVuY3Rpb24gJGZfMiQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTUsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCnBhcihtYWk9YygxLCAwLjgyLCAwLjEsIDAuNDIpKQ0KDQpkYXRhX3llYXIgPC0gZGF0YVtkYXRhJHllYXIgJWluJSBzZXEoMTk2OSwxOTgxLDEpLF0NCmluZCA8LSBkYXRhX3llYXIkaWQNCmF4aXNfbGFiZWxzX2F0IDwtIGFnZ3JlZ2F0ZShkYXRhX3llYXIsIGJ5PWxpc3QoZGF0YV95ZWFyJHllYXIpLCBGVU49bWluKSRpZA0KDQpvYnMgPC0gKCh5W2luZF0taW50ZXJjZXB0WzFdLWYxW2luZCwxXS1mM1tpbmQsMV0tZjRbZGF0YSRkYXlfb2ZfeWVhcjIsMV1baW5kXSkqc3RkX3krbV95KS9tX3kNCnBsb3QoaW5kLCBvYnMsIHR5cGU9InAiLCBsdHk9MSwgcGNoPTIwLCBjZXg9MC42LCBjb2w9Z3JleSgwLjUpLCB4bGFiPSIiLCB5bGFiPSJQcm9wb3J0aW9uIG9mIGJpcnRocyBvdmVyIHRoZSBtZWFuIiwgY2V4LmxhYj0xLjUsIGNleC5heGlzPTEuNiwgeGF4dD0ibiIsIHlsaW09YygwLjg1LDEuMTUpKQ0KDQpheGlzKDEsIGF0PWF4aXNfbGFiZWxzX2F0LCBsYWJlbHM9YXMuY2hhcmFjdGVyKHNlcSgxOTY5LDE5ODEsMSkpLCB0aWNrPVRSVUUsIGNleC5heGlzPTEuNikNCg0KbGluZXMocmFuZ2UoaW5kKSwgYygxLDEpLCBsdHk9MiwgbHdkPTEpCQkJCQkJICAgICAgICAjIG1lYW4NCmxpbmVzKGluZCwgKGYyW2luZCwxXSpzdGRfeSttX3kpL21feSwgY29sPTMsIGx3ZD0yKQkgCQkgICMgZjINCg0KYWJsaW5lKHY9YXhpc19sYWJlbHNfYXQsIGx0eT0yLCBjb2w9Z3JleSgwLjcpKQ0KbGVnZW5kKCJ0b3BsZWZ0IiwgaW5zZXQ9YygwLjA1LDAuMDA1KSwgbGVnZW5kPWMoVGVYKCdPYnNlcnZhdGlvbnMgLSBpbnRlcmNlcHQgLSAkZl8xJCAtICRmXzMkIC0gJGZfNCQnKSxUZVgoJyRmXzIkJykpLCBjb2w9YyhncmV5KDAuNSksMyksIGx0eT1jKE5BLDEpLCBwY2g9YygyMCxOQSksIGx3ZD1jKDMsMyksIGNleD0xLjQsIHhwZD1UUlVFLCBidHk9Im4iLCB5LmludGVyc3A9MSwgeC5pbnRlcnNwPTAuOCwgdGV4dC5mb250PTEsIG5jb2w9MSwgc2VnLmxlbj0xLjMpDQpgYGANCg0KUGxvdCBvZiB0aGUgbWVhbiBwb3N0ZXJpb3IgZnVuY3Rpb24gJGZfMSArIGZfMiQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTUsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCnBhcihtYWk9YygxLCAwLjgyLCAwLjEsIDAuNDIpKQ0KDQpkYXRhX3llYXIgPC0gZGF0YVtkYXRhJHllYXIgJWluJSBzZXEoMTk2OSwxOTgxLDEpLF0NCmluZCA8LSBkYXRhX3llYXIkaWQNCmF4aXNfbGFiZWxzX2F0IDwtIGFnZ3JlZ2F0ZShkYXRhX3llYXIsIGJ5PWxpc3QoZGF0YV95ZWFyJHllYXIpLCBGVU49bWluKSRpZA0KDQpvYnMgPC0gKCh5W2luZF0taW50ZXJjZXB0WzFdLWYzW2luZCwxXS1mNFtkYXRhJGRheV9vZl95ZWFyMiwxXVtpbmRdKSpzdGRfeSttX3kpL21feQ0KcGxvdChpbmQsIG9icywgdHlwZT0icCIsIGx0eT0xLCBwY2g9MjAsIGNleD0wLjYsIGNvbD1ncmV5KDAuNSksIHhsYWI9IiIsIHlsYWI9IlByb3BvcnRpb24gb2YgYmlydGhzIG92ZXIgdGhlIG1lYW4iLCBjZXgubGFiPTEuNSwgY2V4LmF4aXM9MS42LCB4YXh0PSJuIiwgeWxpbT1jKDAuOCwxLjIpKQ0KDQpheGlzKDEsIGF0PWF4aXNfbGFiZWxzX2F0LCBsYWJlbHM9YXMuY2hhcmFjdGVyKHNlcSgxOTY5LDE5ODEsMSkpLCB0aWNrPVRSVUUsIGNleC5heGlzPTEuNikNCg0KbGluZXMocmFuZ2UoaW5kKSwgYygxLDEpLCBsdHk9MiwgbHdkPTEpCQkJCQkJICAgICAgICAgICAgICAgICAgICAjIG1lYW4NCmxpbmVzKGluZCwgKChmMVtpbmQsMV0rZjJbaW5kLDFdKSpzdGRfeSttX3kpL21feSwgY29sPTQsIGx3ZD0yKQkgCQkgICMgZjEgKyBmMg0KDQphYmxpbmUodj1heGlzX2xhYmVsc19hdCwgbHR5PTIsIGNvbD1ncmV5KDAuNykpDQpsZWdlbmQoInRvcGxlZnQiLCBpbnNldD1jKDAuMDUsMC4wMDUpLCBsZWdlbmQ9YyhUZVgoJ09ic2VydmF0aW9ucyAtIGludGVyY2VwdCAtICRmXzMkIC0gJGZfNCQnKSxUZVgoJyRmXzEgKyBmXzIkJykpLCBjb2w9YyhncmV5KDAuNSksNCksIGx0eT1jKE5BLDEpLCBwY2g9YygyMCxOQSksIGx3ZD1jKDMsMyksIGNleD0xLjQsIHhwZD1UUlVFLCBidHk9Im4iLCB5LmludGVyc3A9MSwgeC5pbnRlcnNwPTAuOCwgdGV4dC5mb250PTEsIG5jb2w9MSwgc2VnLmxlbj0xLjMpDQpgYGANCg0KUGxvdCBvZiB0aGUgcmVzaWR1YWxzDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTE1LCBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQpwYXIobWFpPWMoMSwgMC44MiwgMC4xLCAwLjQyKSkNCg0KZGF0YV95ZWFyIDwtIGRhdGFbZGF0YSR5ZWFyICVpbiUgc2VxKDE5NjksMTk4MSwxKSxdDQppbmQgPC0gZGF0YV95ZWFyJGlkDQpheGlzX2xhYmVsc19hdCA8LSBhZ2dyZWdhdGUoZGF0YV95ZWFyLCBieT1saXN0KGRhdGFfeWVhciR5ZWFyKSwgRlVOPW1pbikkaWQNCg0Kb2JzIDwtICgoeVtpbmRdLWludGVyY2VwdFsxXS1mMVtpbmQsMV0tZjJbaW5kLDFdLWYzW2luZCwxXS1mNFtkYXRhJGRheV9vZl95ZWFyMiwxXVtpbmRdKSpzdGRfeSttX3kpL21feQ0KcGxvdChpbmQsIG9icywgdHlwZT0icCIsIGx0eT0xLCBwY2g9MjAsIGNleD0wLjYsIGNvbD1ncmV5KDAuNSksIHhsYWI9IiIsIHlsYWI9IlByb3BvcnRpb24gb2YgYmlydGhzIG92ZXIgdGhlIG1lYW4iLCBjZXgubGFiPTEuNSwgY2V4LmF4aXM9MS42LCB4YXh0PSJuIiwgeWxpbT1jKDAuOCwxLjIpKQ0KDQpheGlzKDEsIGF0PWF4aXNfbGFiZWxzX2F0LCBsYWJlbHM9YXMuY2hhcmFjdGVyKHNlcSgxOTY5LDE5ODEsMSkpLCB0aWNrPVRSVUUsIGNleC5heGlzPTEuNikNCg0KbGluZXMocmFuZ2UoaW5kKSwgYygxLDEpLCBsdHk9MiwgbHdkPTEpCQkJCQkJICAgICAgICAgICAgICAgICAgICAjIG1lYW4NCg0KYWJsaW5lKHY9YXhpc19sYWJlbHNfYXQsIGx0eT0yLCBjb2w9Z3JleSgwLjcpKQ0KbGVnZW5kKCJ0b3BsZWZ0IiwgaW5zZXQ9YygwLjA1LDAuMDA1KSwgbGVnZW5kPWMoVGVYKCdPYnNlcnZhdGlvbnMgLSBpbnRlcmNlcHQgLSAkZl8xJCAtICRmXzIkIC0gJGZfMyQgLSAkZl80JCcpKSwgY29sPWMoZ3JleSgwLjUpLDQpLCBsdHk9YyhOQSwxKSwgcGNoPWMoMjAsTkEpLCBsd2Q9YygzLDMpLCBjZXg9MS40LCB4cGQ9VFJVRSwgYnR5PSJuIiwgeS5pbnRlcnNwPTEsIHguaW50ZXJzcD0wLjgsIHRleHQuZm9udD0xLCBuY29sPTEsIHNlZy5sZW49MS4zKQ0KYGBgDQoNCiMjIyMgTW9kZWwgZXZhbHVhdGlvbg0KDQpSZXNpZHVhbHMNCg0KYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmYgPC0gc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IGMoImYiKSkkc3VtbWFyeVssMV0NCnJlc1tbaV1dIDwtIHN0YW5kYXRhW1tpXV0keSAtIGYNCg0KZ2dwbG90KGFzLmRhdGEuZnJhbWUocmVzW1tpXV0pLCBhZXMocmVzW1tpXV0pKSAgKw0KICBnZW9tX2hpc3RvZ3JhbShjb2xvciA9ICd3aGl0ZScpICsNCiAgdGhlbWVfY2xhc3NpYygpDQpgYGANCg0KUm9vdCBtZWFuIHNxdWFyZWQgZXJyb3INCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCnJtc2VbaV0gPC0gc3FydChtZWFuKHJlc1tbaV1dXjIpKQ0Kcm1zZVtpXQ0KYGBgDQoNCkJheWVzaWFuICRSXjIkIChDb2VmZmljaWVudCBvZiBkZXRlcm1pbmF0aW9uKQ0KDQpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD00LCBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0Kbm9pc2UgPC0gYXMubWF0cml4KGZpdFtbaV1dLCBwYXJzID0gYygibm9pc2UiKSkNCnNkX2YgPC0gYXBwbHkoYXMubWF0cml4KGZpdFtbaV1dLCBwYXJzID0gYygiZiIpKSwgMSwgc2QpDQpSMiA8LSBzZF9mXjIvKHNkX2ZeMiArIG5vaXNlXjIpDQoNCmdncGxvdChhcy5kYXRhLmZyYW1lKFIyKSwgYWVzKFIyKSkgICsNCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3IgPSAnd2hpdGUnKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KYGBgDQoNCk1lZGlhbiBvZiAkUl4yJA0KDQpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD00LCBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KZVIyW2ldIDwtIG1lZGlhbihSMikNCmVSMltpXQ0KYGBgDQoNCkxvZyBwcmVkaWN0aXZlIGRlbnNpdHkgKGxwZCkNCg0KYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxwZCA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygibG9nX2xpayIpKSRzdW1tYXJ5WywxXQ0KDQpnZ3Bsb3QoYXMuZGF0YS5mcmFtZShscGQpLCBhZXMobHBkKSkgICsNCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3IgPSAnd2hpdGUnKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KYGBgDQoNCk1lZGlhbiBvZiBscGQNCg0KYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmVscGRbaV0gPC0gbWVkaWFuKGxwZCkNCmVscGRbaV0NCmBgYA0KDQojIyMjIERpYWdub3Npcw0KDQoqKlNtb290aCB0cmVuZCBmdW5jdGlvbiAkZl8xJCoqDQoNCjEuIEVzdGltYXRlZCBsZW5ndGhzY2FsZSAkXGhhdHtsfSQgIA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mMV9oYXRbaV0gPC0gcm91bmQoc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9ICJsc2NhbGVbMV0iKSRzdW1tYXJ5WywxXSwgMikNCmxfZjFfaGF0W2ldDQpgYGANCg0KMi4gQ2hlY2sgd2hldGhlciAkXGhhdHtsfSQgaXMgZXF1YWwgdG8gb3IgZ3JlYXRlciB0aGFuIGBsX2YxYCAodGhlIG1pbmltdW0gJGwkIHRoYXQgY2FuIGJlIGFjY3VyYXRlbHkgZml0dGVkIGRldGVybWluZWQgYnkgdGhlICRtJCB1c2VkKQ0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mMV9oYXRbaV0gPj0gbF9mMVtpXQ0KYGBgDQoNCioqWWVhcmx5IHBlcmlvZGljIGVmZmVjdHMgZnVuY3Rpb24gJGZfMiQqKg0KDQoxLiBFc3RpbWF0ZWQgbGVuZ3Roc2NhbGUgJFxoYXR7bH0kICANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjJfaGF0W2ldIDwtIHJvdW5kKHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSAibHNjYWxlWzJdIikkc3VtbWFyeVssMV0sIDIpDQpsX2YyX2hhdFtpXQ0KYGBgDQoNCjIuIENoZWNrIHdoZXRoZXIgJFxoYXR7bH0kIGlzIGVxdWFsIHRvIG9yIGdyZWF0ZXIgdGhhbiBgbF9mMmAgKHRoZSBtaW5pbXVtICRsJCB0aGF0IGNhbiBiZSBhY2N1cmF0ZWx5IGZpdHRlZCBkZXRlcm1pbmVkIGJ5IHRoZSAkbSQgdXNlZCkNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjJfaGF0W2ldID49IGxfZjJbaV0NCmBgYA0KDQoqKldlZWtseSBwZXJpb2RpYyBlZmZlY3RzIGZ1bmN0aW9uICRmXzMkKioNCg0KMS4gRXN0aW1hdGVkIGxlbmd0aHNjYWxlICRcaGF0e2x9JCAgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpsX2YzX2hhdFtpXSA8LSByb3VuZChzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gImxzY2FsZVszXSIpJHN1bW1hcnlbLDFdLCAyKQ0KbF9mM19oYXRbaV0NCmBgYA0KDQoyLiBDaGVjayB3aGV0aGVyICRcaGF0e2x9JCBpcyBlcXVhbCB0byBvciBncmVhdGVyIHRoYW4gYGxfZjNgICh0aGUgbWluaW11bSAkbCQgdGhhdCBjYW4gYmUgYWNjdXJhdGVseSBmaXR0ZWQgZGV0ZXJtaW5lZCBieSB0aGUgJG0kIHVzZWQpDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpsX2YzX2hhdFtpXSA+PSBsX2YzW2ldDQpgYGANCg0KKipTdW1tYXJ5IHRhYmxlKioNCg0KYGBge3IgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NSwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZWNobz1GQUxTRX0NCmRpYWdub3Npc1tbaV1dIDwtIGRhdGEuZnJhbWUoaXRlcj0gcmVwKGksMyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHUF9mdW5jPSBjKCJmMSIsImYyIiwiZjMiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGw9IHJvdW5kKGMobF9mMVtpXSxsX2YyW2ldLGxfZjNbaV0pLDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYz0gcm91bmQoYyhjX2YxW2ldLE5BLE5BKSwyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG09IGMobV9mMVtpXSxtX2YyW2ldLG1fZjNbaV0pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbF9oYXQ9IHJvdW5kKGMobF9mMV9oYXRbaV0sbF9mMl9oYXRbaV0sbF9mM19oYXRbaV0pLDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2xfaGF0ID4gbCcgPSBjKGxfZjFfaGF0W2ldID49IGxfZjFbaV0sbF9mMl9oYXRbaV0gPj0gbF9mMltpXSxsX2YzX2hhdFtpXSA+PSBsX2YzW2ldKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJzbWUgPSByb3VuZChyZXAocm1zZVtpXSwzKSwzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFIyID0gcm91bmQocmVwKGVSMltpXSwzKSwzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVscGQgPSByb3VuZChyZXAoZWxwZFtpXSwzKSwzKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQ0KbmFtZXMoZGlhZ25vc2lzW1tpXV0pIDwtIGMoIml0ZXIiLCAiR1BfZnVuYyIsICJsIiwgImMiLCAibSIsICJsX2hhdCIsICJsX2hhdCA+IGwiLCAicm1zZSIsICJSMiIsICJlbHBkIikNCmRpYWdub3Npc1tbaV1dDQpgYGANCg0KIyMjIEl0ZXJhdGlvbiA2DQoNCkl0ZXJhdGlvbiBpbmRleA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KaSA8LSA2DQpgYGANCg0KIyMjIyBTZXR0aW5nICRtJCwgJGwkIGFuZCAkYyQNCg0KKipTbW9vdGggdHJlbmQgZnVuY3Rpb24gJGZfMSQqKg0KDQoxLiBVcGRhdGluZyAkbCQgd2l0aCBpdHMgZXN0aW1hdGUgJFxoYXR7bH0kIGluIHRoZSBmaWZ0aCBpdGVyYXRpb24NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjFbaV0gPC0gbF9mMV9oYXRbaS0xXQ0KbF9mMVtpXQ0KYGBgDQoNCjIuIFRoZSBib3VuZGFyeSBmYWN0b3IgJGMkIGhhcyB0byBmdWxmaWxsICRjIFwsIFxnZXEgXCwgMC45NyArIDEuNDUgXCwgXGZyYWN7bH17U30kDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQowLjk3ICsgMS40NSpsX2YxW2ldL1MNCmBgYA0KDQpUaGVuLCAkYyQgaXMgc2V0IHRvDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpjX2YxW2ldIDwtIDEuNQ0KY19mMVtpXQ0KYGBgDQoNCjMuIFRoZSBudW1iZXIgb2YgYmFzaXMgZnVuY3Rpb25zICRtJCBhcyBhIGZ1bmN0aW9uIG9mICRsJDogICRcOyBtPSAxLjczIFwsIFxmcmFje2N9eyhsL1MpXnsxLjA1fX0kDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQppZigxLjczICogY19mMVtpXS8obF9mMVtpXS9TKV4xLjA1IDwgNSkgbV9mMVtpXSA8LSA1IGVsc2UgbV9mMVtpXSA8LSBjZWlsaW5nKDEuNzMgKiBjX2YxW2ldLyhsX2YxW2ldL1MpXjEuMDUpDQptX2YxW2ldDQpgYGANCg0KKipZZWFybHkgcGVyaW9kaWMgZWZmZWN0cyBmdW5jdGlvbiAkZl8yJCoqDQoNCjEuIFVwZGF0aW5nICRsJCB3aXRoIGl0cyBlc3RpbWF0ZSAkXGhhdHtsfSQgaW4gdGhlIGZpZnRoIGl0ZXJhdGlvbg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mMltpXSA8LSBsX2YyX2hhdFtpLTFdDQpsX2YyW2ldDQpgYGANCg0KMi4gTnVtYmVyIG9mIGJhc2lzIGZ1bmN0aW9ucyAkbSQgYXMgYSBmdW5jdGlvbiBvZiAkbCQ6ICAkXDsgbT0gMy4zMSBcLCBcZnJhY3sxfXtsXnsxLjA1fX0kDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQppZigzLjMxICogMS9sX2YyW2ldXjEuMDUgPCA1KSBtX2YyW2ldIDwtIDUgZWxzZSBtX2YyW2ldIDwtIGNlaWxpbmcoMy4zMSAqIDEvbF9mMltpXV4xLjA1KQ0KbV9mMltpXQ0KYGBgDQoNCioqV2Vla2x5IHBlcmlvZGljIGVmZmVjdHMgZnVuY3Rpb24gJGZfMyQqKg0KDQoxLiBVcGRhdGluZyAkbCQgd2l0aCBpdHMgZXN0aW1hdGUgJFxoYXR7bH0kIGluIHRoZSBmaWZ0aCBpdGVyYXRpb24NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjNbaV0gPC0gbF9mM19oYXRbaS0xXQ0KbF9mM1tpXQ0KYGBgDQoNCjIuIE51bWJlciBvZiBiYXNpcyBmdW5jdGlvbnMgJG0kIGFzIGEgZnVuY3Rpb24gb2YgJGwkOiAgJFw7IG09IDMuMzEgXCwgXGZyYWN7MX17bF57MS4wNX19JA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KaWYoMy4zMSAqIDEvbF9mM1tpXV4xLjA1IDwgNSkgbV9mM1tpXSA8LSA1IGVsc2UgbV9mM1tpXSA8LSBjZWlsaW5nKDMuMzEgKiAxL2xfZjNbaV1eMS4wNSkNCm1fZjNbaV0NCmBgYA0KDQojIyMjIERhdGEgdG8gU3Rhbg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0Kc3RhbmRhdGFbW2ldXSA8LSBsaXN0KE1fZjE9IG1fZjFbaV0sIA0KICAgICAgICAgICAgICAgICBjX2YxPSBjX2YxW2ldLCANCiAgICAgICAgICAgICAgICAgSl9mMj0gbV9mMltpXSwgDQogICAgICAgICAgICAgICAgIEpfZjM9IG1fZjNbaV0sIA0KICAgICAgICAgICAgICAgICB4PSB4WywxXSwgDQogICAgICAgICAgICAgICAgIHk9IHlbLDFdLCANCiAgICAgICAgICAgICAgICAgTj0gbGVuZ3RoKHgpLCANCiAgICAgICAgICAgICAgICAgcGVyaW9kX3llYXI9IHBlcmlvZF95ZWFyLCANCiAgICAgICAgICAgICAgICAgcGVyaW9kX3dlZWs9IHBlcmlvZF93ZWVrLA0KICAgICAgICAgICAgICAgICBkYXlfb2ZfeWVhcjI9IGRheV9vZl95ZWFyMg0KKQ0Kc3RyKHN0YW5kYXRhW1tpXV0pDQpgYGANCg0KIyMjIyBNb2RlbCBmaXR0aW5nDQoNCkNvbXBpbGluZyB0aGUgbW9kZWwNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1UUlVFLCBldmFsPUZBTFNFfQ0KIyBiaXJ0aGRheV9tb2QgPC0gY21kc3RhbnI6OmNtZHN0YW5fbW9kZWwoc3Rhbl9maWxlID0gInN0YW5jb2RlX2RlZi5zdGFuIikNCmBgYA0KDQpNb2RlbCBzYW1wbGluZw0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBldmFsPVRSVUV9DQojIGxvYWQoImZpdC5yRGF0YSIpDQpgYGANCg0KYGBge3Igd2Fybj1UUlVFLCBtZXNzYWdlPUZBTFNFLCBldmFsPUZBTFNFfQ0KIyBmaXRbW2ldXSA8LSBiaXJ0aGRheV9tb2Qkc2FtcGxlKGRhdGE9IHN0YW5kYXRhW1tpXV0sIGl0ZXJfd2FybXVwPTIwMCwgaXRlcl9zYW1wbGluZz0yMDAsIGNoYWlucz00LCB0aGluPTQsIGluaXQ9MC41LCBhZGFwdF9kZWx0YT0wLjksIHNhdmVfd2FybXVwPUZBTFNFKQ0KIyBmaXRbW2ldXSA8LSByc3Rhbjo6cmVhZF9zdGFuX2NzdihmaXRbW2ldXSRvdXRwdXRfZmlsZXMoKSkNCg0KIyBzYXZlKGZpdCwgZmlsZT0iZml0LnJEYXRhIikNCmBgYA0KDQpTdW1tYXJpZXMgb2YgdmFyaWFibGUgZXN0aW1hdGVzDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGV2YWw9VFJVRX0NCnBhcmFtID0gYygiaW50ZXJjZXB0IiwibHNjYWxlWzFdIiwibHNjYWxlWzJdIiwibHNjYWxlWzNdIiwiZ3BzY2FsZVsxXSIsImdwc2NhbGVbMl0iLCJncHNjYWxlWzNdIiwibm9pc2UiLCJzaWdtYV9mNCIpDQpzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gcGFyYW0sIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSksIGRpZ2l0c19zdW1tYXJ5ID0gNCkkc3VtbWFyeQ0KYGBgDQoNClNpbXVsYXRpb24gY2hhaW5zIGZvciB0aGUgdmFyaWFibGVzIGFmdGVyIHdhcm11cA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xNSwgZXZhbD1UUlVFfQ0KdHJhY2VwbG90KGZpdFtbaV1dLCBwYXJzID0gcGFyYW0sIGluY2x1ZGUgPSBUUlVFLCB1bmNvbnN0cmFpbiA9IEZBTFNFLCBpbmNfd2FybXVwID0gRkFMU0UsIHdpbmRvdyA9IE5VTEwsIG5yb3cgPSBOVUxMLCBuY29sID0gTlVMTCkNCmBgYA0KDQpQbG90IG9mIHRoZSBtZWFuIHBvc3RlcmlvciBmdW5jdGlvbiAkZl8xJA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xNSwgZmlnLmFsaWduPSdjZW50ZXInLCBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQpmIDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJmIiksIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSkpJHN1bW1hcnkNCmludGVyY2VwdCA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygiaW50ZXJjZXB0IiksIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSkpJHN1bW1hcnkNCmYxIDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJmMSIpLCBwcm9icyA9IGMoMC4wMjUsIDAuNSwgMC45NzUpKSRzdW1tYXJ5DQpmMiA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygiZjIiKSwgcHJvYnMgPSBjKDAuMDI1LCAwLjUsIDAuOTc1KSkkc3VtbWFyeQ0KZjMgPC0gc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IGMoImYzIiksIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSkpJHN1bW1hcnkNCmY0IDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJmNCIpLCBwcm9icyA9IGMoMC4wMjUsIDAuNSwgMC45NzUpKSRzdW1tYXJ5DQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTUsIGZpZy5hbGlnbj0nY2VudGVyJywgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KcGFyKG1haT1jKDEsIDAuODIsIDAuMSwgMC40MikpDQoNCmluZCA8LSBkYXRhJGlkDQpsYWJlbHNfYXQgPSBhZ2dyZWdhdGUoZGF0YSwgYnk9bGlzdChkYXRhJHllYXIpLCBGVU49bWluKSRpZA0KDQpvYnNfcGx0IDwtICgoeVtpbmRdLWludGVyY2VwdFsxXS1mMltpbmQsMV0tZjNbaW5kLDFdLWY0W2RhdGEkZGF5X29mX3llYXIyLDFdW2luZF0pKnN0ZF95K21feSkvbV95DQpwbG90KGluZCwgb2JzX3BsdCwgdHlwZT0icCIsIHBjaD0yMCwgYmc9Z3JleSgwLjQpLCBjZXg9MC42LCBjb2w9Z3JleSgwLjUpLCB4bGFiPSIiLCB5bGFiPSIiLCBsd2Q9MSwgeWxpbT1jKDAuOCwxLjIpLCBtZ3A9YygzLjUsIDEsIDApLCBmcmFtZS5wbG90PVRSVUUsIHlheHM9InIiLCBjZXguYXhpcz0xLjYsIGNleC5sYWI9MS42LCBsYXM9MSwgeGF4dD0ibiIsIHlheHQ9Im4iLCBmZz1ncmV5KDAuNSksIGZhbWlseT0ic2VyaWYiKQ0KDQpheGlzKDEsIGF0PWxhYmVsc19hdCwgYygiMTk2OSIsIjE5NzAiLCIxOTcxIiwiMTk3MiIsIjE5NzMiLCIxOTc0IiwiMTk3NSIsIjE5NzYiLCIxOTc3IiwiMTk3OCIsIjE5NzkiLCIxOTgwIiwiMTk4MSIsIjE5ODIiLCIxOTgzIiwiMTk4NCIsIjE5ODUiLCIxOTg2IiwiMTk4NyIsIjE5ODgiKSwgdGljaz1UUlVFLCBsdHk9MSwgbWdwPWMoMywgMSwgMCksIGxhcz0xLCBjZXguYXhpcz0xLjYsIGZvbnQ9MSwgY29sPWdyZXkoMC41KSwgY29sLnRpY2tzPWdyZXkoMC4zKSwgZmFtaWx5PSIiKQ0KYXhpcygyLCBhdD1OVUxMLCBsYWJlbHM9VFJVRSwgdGljaz1UUlVFLCBsdHk9MSwgbWdwPWMoMywgMC43LCAwKSwgbGFzPTEsIGNleC5heGlzPTEuNiwgZm9udD01LCBjb2w9Z3JleSgwLjUpLCBjb2wudGlja3M9Z3JleSgwLjMpKQ0KdGl0bGUoeGxhYj0iWWVhciIsIG1ncD1jKDMsIDEsIDApLCBjZXgubGFiPTEuNiwgbGFzPTEpDQp0aXRsZSh5bGFiPSJQcm9wb3J0aW9uIG9mIGJpcnRocyBvdmVyIHRoZSBtZWFuIiwgbWdwPWMoMywgMC43LCAwKSwgY2V4LmxhYj0xLjYsIGxhcz0xKQ0KDQphYmxpbmUoaD0xLCBsdHk9MikJCQkJCQkJCQkJCQkgICAgICAgICAgICAgICAgIyBtZWFuDQpsaW5lcyhpbmQsIChmMVtpbmQsMV0qc3RkX3krbV95KS9tX3ksIGNvbD0yLCBsd2Q9MikJCQkJIyBmMQ0KDQpsZWdlbmQoInRvcGxlZnQiLCBpbnNldD1jKDAuMjIsMC4wMiksIGxlZ2VuZD1jKFRlWCgnT2JzZXJ2YXRpb25zIC0gaW50ZXJjZXB0IC0gJGZfMiQgLSAkZl8zJCAtICRmXzQkJyksVGVYKCckZl8xJCcpKSwgY29sPWMoZ3JleSgwLjQpLDIsMywiZ3JleSIpLCBsdHk9YyhOQSwxLDEsMSksIHBjaD1jKDIwLE5BLE5BLE5BKSwgbHdkPWMoMSwzLDMsMyksIGNleD0xLjQsIHhwZD1UUlVFLCBidHk9Im4iLCB5LmludGVyc3A9MSwgeC5pbnRlcnNwPTAuOCwgdGV4dC5mb250PTEsIG5jb2w9MSwgc2VnLmxlbj0xLjUpDQpgYGANCg0KUGxvdCBvZiB0aGUgbWVhbiBwb3N0ZXJpb3IgZnVuY3Rpb24gJGZfMiQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTUsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCnBhcihtYWk9YygxLCAwLjgyLCAwLjEsIDAuNDIpKQ0KDQpkYXRhX3llYXIgPC0gZGF0YVtkYXRhJHllYXIgJWluJSBzZXEoMTk2OSwxOTgxLDEpLF0NCmluZCA8LSBkYXRhX3llYXIkaWQNCmF4aXNfbGFiZWxzX2F0IDwtIGFnZ3JlZ2F0ZShkYXRhX3llYXIsIGJ5PWxpc3QoZGF0YV95ZWFyJHllYXIpLCBGVU49bWluKSRpZA0KDQpvYnMgPC0gKCh5W2luZF0taW50ZXJjZXB0WzFdLWYxW2luZCwxXS1mM1tpbmQsMV0tZjRbZGF0YSRkYXlfb2ZfeWVhcjIsMV1baW5kXSkqc3RkX3krbV95KS9tX3kNCnBsb3QoaW5kLCBvYnMsIHR5cGU9InAiLCBsdHk9MSwgcGNoPTIwLCBjZXg9MC42LCBjb2w9Z3JleSgwLjUpLCB4bGFiPSIiLCB5bGFiPSJQcm9wb3J0aW9uIG9mIGJpcnRocyBvdmVyIHRoZSBtZWFuIiwgY2V4LmxhYj0xLjUsIGNleC5heGlzPTEuNiwgeGF4dD0ibiIsIHlsaW09YygwLjg1LDEuMTUpKQ0KDQpheGlzKDEsIGF0PWF4aXNfbGFiZWxzX2F0LCBsYWJlbHM9YXMuY2hhcmFjdGVyKHNlcSgxOTY5LDE5ODEsMSkpLCB0aWNrPVRSVUUsIGNleC5heGlzPTEuNikNCg0KbGluZXMocmFuZ2UoaW5kKSwgYygxLDEpLCBsdHk9MiwgbHdkPTEpCQkJCQkJICAgICAgICAjIG1lYW4NCmxpbmVzKGluZCwgKGYyW2luZCwxXSpzdGRfeSttX3kpL21feSwgY29sPTMsIGx3ZD0yKQkgCQkgICMgZjINCg0KYWJsaW5lKHY9YXhpc19sYWJlbHNfYXQsIGx0eT0yLCBjb2w9Z3JleSgwLjcpKQ0KbGVnZW5kKCJ0b3BsZWZ0IiwgaW5zZXQ9YygwLjA1LDAuMDA1KSwgbGVnZW5kPWMoVGVYKCdPYnNlcnZhdGlvbnMgLSBpbnRlcmNlcHQgLSAkZl8xJCAtICRmXzMkIC0gJGZfNCQnKSxUZVgoJyRmXzIkJykpLCBjb2w9YyhncmV5KDAuNSksMyksIGx0eT1jKE5BLDEpLCBwY2g9YygyMCxOQSksIGx3ZD1jKDMsMyksIGNleD0xLjQsIHhwZD1UUlVFLCBidHk9Im4iLCB5LmludGVyc3A9MSwgeC5pbnRlcnNwPTAuOCwgdGV4dC5mb250PTEsIG5jb2w9MSwgc2VnLmxlbj0xLjMpDQpgYGANCg0KUGxvdCBvZiB0aGUgbWVhbiBwb3N0ZXJpb3IgZnVuY3Rpb24gJGZfMSArIGZfMiQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTUsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCnBhcihtYWk9YygxLCAwLjgyLCAwLjEsIDAuNDIpKQ0KDQpkYXRhX3llYXIgPC0gZGF0YVtkYXRhJHllYXIgJWluJSBzZXEoMTk2OSwxOTgxLDEpLF0NCmluZCA8LSBkYXRhX3llYXIkaWQNCmF4aXNfbGFiZWxzX2F0IDwtIGFnZ3JlZ2F0ZShkYXRhX3llYXIsIGJ5PWxpc3QoZGF0YV95ZWFyJHllYXIpLCBGVU49bWluKSRpZA0KDQpvYnMgPC0gKCh5W2luZF0taW50ZXJjZXB0WzFdLWYzW2luZCwxXS1mNFtkYXRhJGRheV9vZl95ZWFyMiwxXVtpbmRdKSpzdGRfeSttX3kpL21feQ0KcGxvdChpbmQsIG9icywgdHlwZT0icCIsIGx0eT0xLCBwY2g9MjAsIGNleD0wLjYsIGNvbD1ncmV5KDAuNSksIHhsYWI9IiIsIHlsYWI9IlByb3BvcnRpb24gb2YgYmlydGhzIG92ZXIgdGhlIG1lYW4iLCBjZXgubGFiPTEuNSwgY2V4LmF4aXM9MS42LCB4YXh0PSJuIiwgeWxpbT1jKDAuOCwxLjIpKQ0KDQpheGlzKDEsIGF0PWF4aXNfbGFiZWxzX2F0LCBsYWJlbHM9YXMuY2hhcmFjdGVyKHNlcSgxOTY5LDE5ODEsMSkpLCB0aWNrPVRSVUUsIGNleC5heGlzPTEuNikNCg0KbGluZXMocmFuZ2UoaW5kKSwgYygxLDEpLCBsdHk9MiwgbHdkPTEpCQkJCQkJICAgICAgICAgICAgICAgICAgICAjIG1lYW4NCmxpbmVzKGluZCwgKChmMVtpbmQsMV0rZjJbaW5kLDFdKSpzdGRfeSttX3kpL21feSwgY29sPTQsIGx3ZD0yKQkgCQkgICMgZjEgKyBmMg0KDQphYmxpbmUodj1heGlzX2xhYmVsc19hdCwgbHR5PTIsIGNvbD1ncmV5KDAuNykpDQpsZWdlbmQoInRvcGxlZnQiLCBpbnNldD1jKDAuMDUsMC4wMDUpLCBsZWdlbmQ9YyhUZVgoJ09ic2VydmF0aW9ucyAtIGludGVyY2VwdCAtICRmXzMkIC0gJGZfNCQnKSxUZVgoJyRmXzEgKyBmXzIkJykpLCBjb2w9YyhncmV5KDAuNSksNCksIGx0eT1jKE5BLDEpLCBwY2g9YygyMCxOQSksIGx3ZD1jKDMsMyksIGNleD0xLjQsIHhwZD1UUlVFLCBidHk9Im4iLCB5LmludGVyc3A9MSwgeC5pbnRlcnNwPTAuOCwgdGV4dC5mb250PTEsIG5jb2w9MSwgc2VnLmxlbj0xLjMpDQpgYGANCg0KUGxvdCBvZiB0aGUgcmVzaWR1YWxzDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTE1LCBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQpwYXIobWFpPWMoMSwgMC44MiwgMC4xLCAwLjQyKSkNCg0KZGF0YV95ZWFyIDwtIGRhdGFbZGF0YSR5ZWFyICVpbiUgc2VxKDE5NjksMTk4MSwxKSxdDQppbmQgPC0gZGF0YV95ZWFyJGlkDQpheGlzX2xhYmVsc19hdCA8LSBhZ2dyZWdhdGUoZGF0YV95ZWFyLCBieT1saXN0KGRhdGFfeWVhciR5ZWFyKSwgRlVOPW1pbikkaWQNCg0Kb2JzIDwtICgoeVtpbmRdLWludGVyY2VwdFsxXS1mMVtpbmQsMV0tZjJbaW5kLDFdLWYzW2luZCwxXS1mNFtkYXRhJGRheV9vZl95ZWFyMiwxXVtpbmRdKSpzdGRfeSttX3kpL21feQ0KcGxvdChpbmQsIG9icywgdHlwZT0icCIsIGx0eT0xLCBwY2g9MjAsIGNleD0wLjYsIGNvbD1ncmV5KDAuNSksIHhsYWI9IiIsIHlsYWI9IlByb3BvcnRpb24gb2YgYmlydGhzIG92ZXIgdGhlIG1lYW4iLCBjZXgubGFiPTEuNSwgY2V4LmF4aXM9MS42LCB4YXh0PSJuIiwgeWxpbT1jKDAuOCwxLjIpKQ0KDQpheGlzKDEsIGF0PWF4aXNfbGFiZWxzX2F0LCBsYWJlbHM9YXMuY2hhcmFjdGVyKHNlcSgxOTY5LDE5ODEsMSkpLCB0aWNrPVRSVUUsIGNleC5heGlzPTEuNikNCg0KbGluZXMocmFuZ2UoaW5kKSwgYygxLDEpLCBsdHk9MiwgbHdkPTEpCQkJCQkJICAgICAgICAgICAgICAgICAgICAjIG1lYW4NCg0KYWJsaW5lKHY9YXhpc19sYWJlbHNfYXQsIGx0eT0yLCBjb2w9Z3JleSgwLjcpKQ0KbGVnZW5kKCJ0b3BsZWZ0IiwgaW5zZXQ9YygwLjA1LDAuMDA1KSwgbGVnZW5kPWMoVGVYKCdPYnNlcnZhdGlvbnMgLSBpbnRlcmNlcHQgLSAkZl8xJCAtICRmXzIkIC0gJGZfMyQgLSAkZl80JCcpKSwgY29sPWMoZ3JleSgwLjUpLDQpLCBsdHk9YyhOQSwxKSwgcGNoPWMoMjAsTkEpLCBsd2Q9YygzLDMpLCBjZXg9MS40LCB4cGQ9VFJVRSwgYnR5PSJuIiwgeS5pbnRlcnNwPTEsIHguaW50ZXJzcD0wLjgsIHRleHQuZm9udD0xLCBuY29sPTEsIHNlZy5sZW49MS4zKQ0KYGBgDQoNCiMjIyMgTW9kZWwgZXZhbHVhdGlvbg0KDQpSZXNpZHVhbHMNCg0KYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmYgPC0gc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IGMoImYiKSkkc3VtbWFyeVssMV0NCnJlc1tbaV1dIDwtIHN0YW5kYXRhW1tpXV0keSAtIGYNCg0KZ2dwbG90KGFzLmRhdGEuZnJhbWUocmVzW1tpXV0pLCBhZXMocmVzW1tpXV0pKSAgKw0KICBnZW9tX2hpc3RvZ3JhbShjb2xvciA9ICd3aGl0ZScpICsNCiAgdGhlbWVfY2xhc3NpYygpDQpgYGANCg0KUm9vdCBtZWFuIHNxdWFyZWQgZXJyb3INCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCnJtc2VbaV0gPC0gc3FydChtZWFuKHJlc1tbaV1dXjIpKQ0Kcm1zZVtpXQ0KYGBgDQoNCkJheWVzaWFuICRSXjIkIChDb2VmZmljaWVudCBvZiBkZXRlcm1pbmF0aW9uKQ0KDQpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD00LCBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0Kbm9pc2UgPC0gYXMubWF0cml4KGZpdFtbaV1dLCBwYXJzID0gYygibm9pc2UiKSkNCnNkX2YgPC0gYXBwbHkoYXMubWF0cml4KGZpdFtbaV1dLCBwYXJzID0gYygiZiIpKSwgMSwgc2QpDQpSMiA8LSBzZF9mXjIvKHNkX2ZeMiArIG5vaXNlXjIpDQoNCmdncGxvdChhcy5kYXRhLmZyYW1lKFIyKSwgYWVzKFIyKSkgICsNCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3IgPSAnd2hpdGUnKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KYGBgDQoNCk1lZGlhbiBvZiAkUl4yJA0KDQpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD00LCBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KZVIyW2ldIDwtIG1lZGlhbihSMikNCmVSMltpXQ0KYGBgDQoNCkxvZyBwcmVkaWN0aXZlIGRlbnNpdHkgKGxwZCkNCg0KYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxwZCA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygibG9nX2xpayIpKSRzdW1tYXJ5WywxXQ0KDQpnZ3Bsb3QoYXMuZGF0YS5mcmFtZShscGQpLCBhZXMobHBkKSkgICsNCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3IgPSAnd2hpdGUnKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KYGBgDQoNCk1lZGlhbiBvZiBscGQNCg0KYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmVscGRbaV0gPC0gbWVkaWFuKGxwZCkNCmVscGRbaV0NCmBgYA0KDQojIyMjIERpYWdub3Npcw0KDQoqKlNtb290aCB0cmVuZCBmdW5jdGlvbiAkZl8xJCoqDQoNCjEuIEVzdGltYXRlZCBsZW5ndGhzY2FsZSAkXGhhdHtsfSQgIA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mMV9oYXRbaV0gPC0gcm91bmQoc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9ICJsc2NhbGVbMV0iKSRzdW1tYXJ5WywxXSwgMikNCmxfZjFfaGF0W2ldDQpgYGANCg0KMi4gQ2hlY2sgd2hldGhlciAkXGhhdHtsfSQgaXMgZXF1YWwgdG8gb3IgZ3JlYXRlciB0aGFuIGBsX2YxYCAodGhlIG1pbmltdW0gJGwkIHRoYXQgY2FuIGJlIGFjY3VyYXRlbHkgZml0dGVkIGRldGVybWluZWQgYnkgdGhlICRtJCB1c2VkKQ0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuPUZBTFNFfQ0KbF9mMV9oYXRbaV0gPj0gbF9mMVtpXQ0KYGBgDQoNCioqWWVhcmx5IHBlcmlvZGljIGVmZmVjdHMgZnVuY3Rpb24gJGZfMiQqKg0KDQoxLiBFc3RpbWF0ZWQgbGVuZ3Roc2NhbGUgJFxoYXR7bH0kICANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjJfaGF0W2ldIDwtIHJvdW5kKHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSAibHNjYWxlWzJdIikkc3VtbWFyeVssMV0sIDIpDQpsX2YyX2hhdFtpXQ0KYGBgDQoNCjIuIENoZWNrIHdoZXRoZXIgJFxoYXR7bH0kIGlzIGVxdWFsIHRvIG9yIGdyZWF0ZXIgdGhhbiBgbF9mMmAgKHRoZSBtaW5pbXVtICRsJCB0aGF0IGNhbiBiZSBhY2N1cmF0ZWx5IGZpdHRlZCBkZXRlcm1pbmVkIGJ5IHRoZSAkbSQgdXNlZCkNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRX0NCmxfZjJfaGF0W2ldID49IGxfZjJbaV0NCmBgYA0KDQoqKldlZWtseSBwZXJpb2RpYyBlZmZlY3RzIGZ1bmN0aW9uICRmXzMkKioNCg0KMS4gRXN0aW1hdGVkIGxlbmd0aHNjYWxlICRcaGF0e2x9JCAgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpsX2YzX2hhdFtpXSA8LSByb3VuZChzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gImxzY2FsZVszXSIpJHN1bW1hcnlbLDFdLCAyKQ0KbF9mM19oYXRbaV0NCmBgYA0KDQoyLiBDaGVjayB3aGV0aGVyICRcaGF0e2x9JCBpcyBlcXVhbCB0byBvciBncmVhdGVyIHRoYW4gYGxfZjNgICh0aGUgbWluaW11bSAkbCQgdGhhdCBjYW4gYmUgYWNjdXJhdGVseSBmaXR0ZWQgZGV0ZXJtaW5lZCBieSB0aGUgJG0kIHVzZWQpDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0V9DQpsX2YzX2hhdFtpXSA+PSBsX2YzW2ldDQpgYGANCg0KKipTdW1tYXJ5IHRhYmxlKioNCg0KYGBge3IgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NSwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZWNobz1GQUxTRX0NCmRpYWdub3Npc1tbaV1dIDwtIGRhdGEuZnJhbWUoaXRlcj0gcmVwKGksMyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHUF9mdW5jPSBjKCJmMSIsImYyIiwiZjMiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGw9IHJvdW5kKGMobF9mMVtpXSxsX2YyW2ldLGxfZjNbaV0pLDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYz0gcm91bmQoYyhjX2YxW2ldLE5BLE5BKSwyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG09IGMobV9mMVtpXSxtX2YyW2ldLG1fZjNbaV0pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbF9oYXQ9IHJvdW5kKGMobF9mMV9oYXRbaV0sbF9mMl9oYXRbaV0sbF9mM19oYXRbaV0pLDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2xfaGF0ID4gbCcgPSBjKGxfZjFfaGF0W2ldID49IGxfZjFbaV0sbF9mMl9oYXRbaV0gPj0gbF9mMltpXSxsX2YzX2hhdFtpXSA+PSBsX2YzW2ldKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJzbWUgPSByb3VuZChyZXAocm1zZVtpXSwzKSwzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFIyID0gcm91bmQocmVwKGVSMltpXSwzKSwzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVscGQgPSByb3VuZChyZXAoZWxwZFtpXSwzKSwzKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApDQpuYW1lcyhkaWFnbm9zaXNbW2ldXSkgPC0gYygiaXRlciIsICJHUF9mdW5jIiwgImwiLCAiYyIsICJtIiwgImxfaGF0IiwgImxfaGF0ID4gbCIsICJybXNlIiwgIlIyIiwgImVscGQiKQ0KZGlhZ25vc2lzW1tpXV0NCmBgYA0KDQojIyMgR2xvYmFsIHN1bW1hcnkgb2YgdGhlIGRpYWdub3NpcyAod2l0aCBhbGwgaXRlcmF0aW9ucykNCg0KYGBge3IgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NSwgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZWNobz1GQUxTRX0NCmRpYWdub3Npc19zdW1tIDwtIHJiaW5kKGRpYWdub3Npc1tbMV1dLGRpYWdub3Npc1tbMl1dLGRpYWdub3Npc1tbM11dLGRpYWdub3Npc1tbNF1dLGRpYWdub3Npc1tbNV1dLGRpYWdub3Npc1tbNl1dKQ0KDQpkaWFnbm9zaXNfc3VtbVtkaWFnbm9zaXNfc3VtbSRHUF9mdW5jPT0iZjEiLF0NCmRpYWdub3Npc19zdW1tW2RpYWdub3Npc19zdW1tJEdQX2Z1bmM9PSJmMiIsXQ0KZGlhZ25vc2lzX3N1bW1bZGlhZ25vc2lzX3N1bW0kR1BfZnVuYz09ImYzIixdDQpgYGANCg0KIyMgUGxvdHMgb2YgdGhlIG1lYW4gcG9zdGVyaW9yIGZ1bmN0aW9ucyBmcm9tIHRoZSBsYXN0IGl0ZXJhdGlvbg0KDQpFeHRyYWN0aW5nIGVzdGltYXRlZCBmdW5jdGlvbiBjb21wb25lbnRzICRmXzEkLCAkZl8yJCwgJGZfMyQgYW5kICRmXzQkDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGV2YWw9VFJVRX0NCmYgPC0gc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IGMoImYiKSwgcHJvYnMgPSBjKDAuMDI1LCAwLjUsIDAuOTc1KSkkc3VtbWFyeQ0KaW50ZXJjZXB0IDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJpbnRlcmNlcHQiKSwgcHJvYnMgPSBjKDAuMDI1LCAwLjUsIDAuOTc1KSkkc3VtbWFyeQ0KZjEgPC0gc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IGMoImYxIiksIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSkpJHN1bW1hcnkNCmYyIDwtIHN1bW1hcnkoZml0W1tpXV0sIHBhcnMgPSBjKCJmMiIpLCBwcm9icyA9IGMoMC4wMjUsIDAuNSwgMC45NzUpKSRzdW1tYXJ5DQpmMyA8LSBzdW1tYXJ5KGZpdFtbaV1dLCBwYXJzID0gYygiZjMiKSwgcHJvYnMgPSBjKDAuMDI1LCAwLjUsIDAuOTc1KSkkc3VtbWFyeQ0KZjQgPC0gc3VtbWFyeShmaXRbW2ldXSwgcGFycyA9IGMoImY0IiksIHByb2JzID0gYygwLjAyNSwgMC41LCAwLjk3NSkpJHN1bW1hcnkNCmBgYA0KDQojIyMjIFBsb3Qgb2Ygb25seSBvbmUgeWVhciwgdGhlIHllYXIgMTk3MiANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTQsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCmRhdGFfeWVhciA8LSBkYXRhW2RhdGEkeWVhcj09MTk3MixdDQppbmQgPC0gZGF0YV95ZWFyJGlkDQpheGlzX2xhYmVsc19hdCA8LSBhZ2dyZWdhdGUoZGF0YV95ZWFyLCBieT1saXN0KGRhdGFfeWVhciRtb250aCksIEZVTj1taW4pJGlkDQoNCnBhcihtYWk9YygxLCAwLjgyLCAwLjEsIDAuNDIpKQ0KDQpwbG90KGluZCwgKHlbaW5kXSpzdGRfeSttX3kpL21feSwgdHlwZT0icCIsIHBjaD0yMSwgYmc9Z3JleSgwLjcpLCBjZXg9MC45LCBjb2w9Z3JleSgwLjQpLCB4bGFiPSIiLCB5bGFiPSIiLCBsd2Q9MSwgeWxpbT1jKDAuNzMsMS4xNiksIG1ncD0gYygyLCAxLCAwKSwgZnJhbWUucGxvdCA9IFRSVUUsIHlheHM9InIiLCBjZXguYXhpcz0xLjYsIGNleC5sYWI9MS42LCBsYXM9MSwgeGF4dD0ibiIsIHlheHQ9Im4iLCBmZz1ncmV5KDAuNSksIGZhbWlseT0ic2VyaWYiKQ0KYXhpcygxLCBhdD1heGlzX2xhYmVsc19hdCwgbGFiZWxzPWMoIkphbiIsIkZlYiIsIk1hciIsIkFwciIsIk1heSIsIkp1biIsIkp1bCIsIkF1ZyIsIlNlcCIsIk9jdCIsIk5vdiIsIkRlYyIpLCB0aWNrPVRSVUUsIGx0eT0xLCBtZ3A9YygyLCAxLCAwKSwgbGFzPTEsIGNleC5heGlzPTEuNiwgZm9udD0xLCBjb2w9Z3JleSgwLjUpLCBjb2wudGlja3M9Z3JleSgwLjMpLCBmYW1pbHk9IiIpDQpheGlzKDIsIGF0PU5VTEwsIGxhYmVscz1UUlVFLCB0aWNrPVRSVUUsIGx0eT0xLCBtZ3A9YygzLCAwLjcsIDApLCBsYXM9MSwgY2V4LmF4aXM9MS42LCBmb250PTUsIGNvbD1ncmV5KDAuNSksIGNvbC50aWNrcz1ncmV5KDAuMykpDQp0aXRsZSh4bGFiID0iTW9udGgiLCBtZ3A9IGMoMywgMSwgMCksIGNleC5sYWI9MS42LCBsYXM9MSkNCnRpdGxlKHlsYWIgPSJQcm9wb3J0aW9uIG9mIGJpcnRocyBvdmVyIHRoZSBtZWFuIiwgbWdwPSBjKDMsIDAuNywgMCksIGNleC5sYWI9MS42LCBsYXM9MSkNCgkNCmxpbmVzKGluZCwgKChmW2luZCwxXStpbnRlcmNlcHRbMV0pKnN0ZF95K21feSkvbV95LCBjb2w9Z3JleSgwLjYpLCBsd2Q9MSkJICAgICMgZg0KYWJsaW5lKGg9MSwgbHR5PTIpCQkJCQkJICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBtZWFuDQpsaW5lcyhpbmQsICgoZjFbaW5kLDFdK2ludGVyY2VwdFsxXSkqc3RkX3krbV95KS9tX3ksIGNvbD0yLCBsd2Q9MikJCQkgICAgICAjIGYxIA0KbGluZXMoaW5kLCAoKGYxW2luZCwxXStpbnRlcmNlcHRbMV0rZjJbaW5kLDFdKSpzdGRfeSttX3kpL21feSwgY29sPTMsIGx3ZD0yKQkjIGYxICsgZjIgDQpsaW5lcyhpbmQsIChmNFtkYXRhJGRheV9vZl95ZWFyMiwxXVtpbmRdKnN0ZF95K21feSkvbV95LCBjb2w9NiwgbHdkPTEpIAkJICAgICMgZjQgDQoNCiNsYWJlbHMgc3BlY2lhbCBkYXlzDQp0ZXh0KGluZFtkYXRhX3llYXIkbW9udGg9PTEmZGF0YV95ZWFyJGRheT09MV0rMiwgeSA9IDAuODQsIGxhYmVscyA9ICJOZXcgeWVhciIsIHBvcyA9TlVMTCwgb2Zmc2V0ID0gMCwgZmFtaWx5PSJzZXJpZiIsIGNleD0xLjMpDQp0ZXh0KGluZFtkYXRhX3llYXIkbW9udGg9PTImZGF0YV95ZWFyJGRheT09MTRdLCB5ID0gMS4wNDUsIGxhYmVscyA9ICJWYWxlbnRpbmUncyBkYXkiLCBwb3MgPU5VTEwsIG9mZnNldCA9IDAsIGZhbWlseT0ic2VyaWYiLCBjZXg9MS4zKQ0KdGV4dChpbmRbZGF0YV95ZWFyJG1vbnRoPT0yJmRhdGFfeWVhciRkYXk9PTI5XSwgeSA9IDAuOTc4LCBsYWJlbHMgPSAiTGVhcCBkYXkiLCBwb3MgPU5VTEwsIG9mZnNldCA9IDAsIGZhbWlseT0ic2VyaWYiLCBjZXg9MS4zKQ0KdGV4dChpbmRbZGF0YV95ZWFyJG1vbnRoPT00JmRhdGFfeWVhciRkYXk9PTFdKzIsIHkgPSAwLjk4MCwgbGFiZWxzID0gIkFwcmlsIDFzdCIsIHBvcyA9TlVMTCwgb2Zmc2V0ID0gMCwgZmFtaWx5PSJzZXJpZiIsIGNleD0xLjMpDQp0ZXh0KGluZFtkYXRhX3llYXIkbW9udGg9PTUmZGF0YV95ZWFyJGRheT09MjddLCB5ID0gMC45OCwgbGFiZWxzID0gIk1lbW9yaWFsIGRheSIsIHBvcyA9TlVMTCwgb2Zmc2V0ID0gMCwgZmFtaWx5PSJzZXJpZiIsIGNleD0xLjMpDQp0ZXh0KGluZFtkYXRhX3llYXIkbW9udGg9PTcmZGF0YV95ZWFyJGRheT09NF0sIHkgPSAwLjg2LCBsYWJlbHMgPSAiSW5kZXBlbmRlbmNlIGRheSIsIHBvcyA9TlVMTCwgb2Zmc2V0ID0gMCwgZmFtaWx5PSJzZXJpZiIsIGNleD0xLjMpDQp0ZXh0KGluZFtkYXRhX3llYXIkbW9udGg9PTkmZGF0YV95ZWFyJGRheT09Ml0sIHkgPSAwLjk3LCBsYWJlbHMgPSAiTGFib3IgZGF5IiwgcG9zID1OVUxMLCBvZmZzZXQgPSAwLCBmYW1pbHk9InNlcmlmIiwgY2V4PTEuMykNCnRleHQoaW5kW2RhdGFfeWVhciRtb250aD09MTAmZGF0YV95ZWFyJGRheT09MzBdKzIsIHkgPSAwLjk4NSwgbGFiZWxzID0gIkhhbGxvd2VlbiIsIHBvcyA9TlVMTCwgb2Zmc2V0ID0gMCwgZmFtaWx5PSJzZXJpZiIsIGNleD0xLjMpDQp0ZXh0KGluZFtkYXRhX3llYXIkbW9udGg9PTExJmRhdGFfeWVhciRkYXk9PTI1XSs1LCB5ID0gMC45NSwgbGFiZWxzID0gIlRoYW5rcy1naXZpbmciLCBwb3MgPU5VTEwsIG9mZnNldCA9IDAsIGZhbWlseT0ic2VyaWYiLCBjZXg9MS4zKQ0KdGV4dChpbmRbZGF0YV95ZWFyJG1vbnRoPT0xMiZkYXRhX3llYXIkZGF5PT0yNV0sIHkgPSAwLjgyLCBsYWJlbHMgPSAiQ2hyaXN0bWFzIiwgcG9zID1OVUxMLCBvZmZzZXQgPSAwLCBmYW1pbHk9InNlcmlmIiwgY2V4PTEuMykNCg0KbGVnZW5kKCJ0b3BsZWZ0IiwgaW5zZXQ9YygwLjA1LDAuMDEpLCBsZWdlbmQ9YygiT2JzZXJ2YXRpb25zIixUZVgoJyRmXzEkJyksVGVYKCckZl8xICsgZl8yJCcpLFRlWCgnJGZfNCQnKSxUZVgoJyRmXzEgKyBmXzIgKyBmXzMgKyBmXzQkJykpLCBjb2w9YyhncmV5KDAuNSksMiwzLDYsZ3JleSgwLjUpKSwgbHR5PWMoTkEsMSwxLDEsMSksIHBjaD1jKDIwLE5BLE5BLE5BLE5BKSwgbHdkPWMoMiwzLDMsMywzKSwgY2V4PTEuNCwgeHBkPVRSVUUsIGJ0eT0ibiIsIHkuaW50ZXJzcD0xLCB4LmludGVyc3A9MC44LCB0ZXh0LmZvbnQ9MSwgbmNvbD0yLCBzZWcubGVuPTEuMykNCmBgYA0KDQoNCiMjIyMgUGxvdCBvZiBhbGwgdGhlIHllYXJzDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTE0LCBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQpwYXIobWFpPWMoMSwgMC44MiwgMC4xLCAwLjQyKSkNCg0KaW5kIDwtIGRhdGEkaWQNCmxhYmVsc19hdCA9IGFnZ3JlZ2F0ZShkYXRhLCBieT1saXN0KGRhdGEkeWVhciksIEZVTj1taW4pJGlkDQpwbG90KGluZCwgKHlbaW5kXSpzdGRfeSttX3kpL21feSwgdHlwZT0icCIsIHBjaD0yMCwgYmc9Z3JleSgwLjQpLCBjZXg9MC42LCBjb2w9Z3JleSgwLjUpLCB4bGFiPSIiLCB5bGFiPSIiLCBsd2Q9MSwgeWxpbT1jKDAuNywxLjMpLCBtZ3A9YygzLjUsIDEsIDApLCBmcmFtZS5wbG90PVRSVUUsIHlheHM9InIiLCBjZXguYXhpcz0xLjYsIGNleC5sYWI9MS42LCBsYXM9MSwgeGF4dD0ibiIsIHlheHQ9Im4iLCBmZz1ncmV5KDAuNSksIGZhbWlseT0ic2VyaWYiKQ0KDQpheGlzKDEsIGF0PWxhYmVsc19hdCwgYygiMTk2OSIsIjE5NzAiLCIxOTcxIiwiMTk3MiIsIjE5NzMiLCIxOTc0IiwiMTk3NSIsIjE5NzYiLCIxOTc3IiwiMTk3OCIsIjE5NzkiLCIxOTgwIiwiMTk4MSIsIjE5ODIiLCIxOTgzIiwiMTk4NCIsIjE5ODUiLCIxOTg2IiwiMTk4NyIsIjE5ODgiKSwgdGljaz1UUlVFLCBsdHk9MSwgbWdwPWMoMywgMSwgMCksIGxhcz0xLCBjZXguYXhpcz0xLjYsIGZvbnQ9MSwgY29sPWdyZXkoMC41KSwgY29sLnRpY2tzPWdyZXkoMC4zKSwgZmFtaWx5PSIiKQ0KYXhpcygyLCBhdD1OVUxMLCBsYWJlbHM9VFJVRSwgdGljaz1UUlVFLCBsdHk9MSwgbWdwPWMoMywgMC43LCAwKSwgbGFzPTEsIGNleC5heGlzPTEuNiwgZm9udD01LCBjb2w9Z3JleSgwLjUpLCBjb2wudGlja3M9Z3JleSgwLjMpKQ0KdGl0bGUoeGxhYj0iWWVhciIsIG1ncD1jKDMsIDEsIDApLCBjZXgubGFiPTEuNiwgbGFzPTEpDQp0aXRsZSh5bGFiPSJQcm9wb3J0aW9uIG9mIGJpcnRocyBvdmVyIHRoZSBtZWFuIiwgbWdwPWMoMywgMC43LCAwKSwgY2V4LmxhYj0xLjYsIGxhcz0xKQ0KDQphYmxpbmUoaD0xLCBsdHk9MikJCQkJCQkJCQkJCQkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBtZWFuDQpsaW5lcyhpbmQsICgoZjFbaW5kLDFdK2ludGVyY2VwdFsxXSkqc3RkX3krbV95KS9tX3ksIGNvbD0yLCBsd2Q9MikJCQkJICAgICAgICAjIGYxDQpsaW5lcyhpbmQsICgoZjFbaW5kLDFdK2ludGVyY2VwdFsxXStmMltpbmQsMV0pKnN0ZF95K21feSkvbV95LCBjb2w9MywgbHdkPTIpCQkJIyBmMSArIGYyDQoNCmxlZ2VuZCgidG9wbGVmdCIsIGluc2V0PWMoMC4yMiwwLjAyKSwgbGVnZW5kPWMoIk9ic2VydmF0aW9ucyIsVGVYKCckZl8xJCcpLFRlWCgnJGZfMSArIGZfMiQnKSksIGNvbD1jKGdyZXkoMC40KSwyLDMsImdyZXkiKSwgbHR5PWMoTkEsMSwxLDEpLCBwY2g9YygyMCxOQSxOQSxOQSksIGx3ZD1jKDEsMywzLDMpLCBjZXg9MS40LCB4cGQ9VFJVRSwgYnR5PSJuIiwgeS5pbnRlcnNwPTEsIHguaW50ZXJzcD0wLjgsIHRleHQuZm9udD0xLCBuY29sPTEsIHNlZy5sZW49MS41KQ0KYGBgDQoNCiMjIyMgUGxvdCBvZiBvbmx5IHRoZSBmaXJzdCBtb250aCANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2Fybj1GQUxTRSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTQsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCnBhcihtYWk9YygxLCAwLjgyLCAwLjEsIDAuNDIpKQ0KDQpkYXRhX21vbnRoIDwtIGRhdGFbZGF0YSRtb250aD09MSZkYXRhJHllYXI9PTE5NzIsXQ0KaW5kIDwtIGRhdGFfbW9udGgkaWQNCmF4aXNfbGFiZWxzX2F0IDwtIGFnZ3JlZ2F0ZShkYXRhX21vbnRoLCBieT1saXN0KGRhdGFfbW9udGgkZGF5KSwgRlVOPW1pbikkaWQNCg0KaWRfd2VlayA8LSBkYXRhX21vbnRoJGlkW2RhdGFfbW9udGgkZGF5X29mX3dlZWs9PTFdDQoNCnBsb3QoaW5kLCAoeVtpbmRdKnN0ZF95K21feSkvbV95LCB0eXBlPSJwIiwgcGNoPTIxLCBiZz1ncmV5KDAuNyksIGNleD0xLjIsIGNvbD1ncmV5KDAuNCksIHhsYWI9IiIsIHlsYWI9IiIsIGx3ZD0xLCB5bGltPWMoMC43LDEuMiksIG1ncD1jKDMuNSwgMSwgMCksIGZyYW1lLnBsb3Q9VFJVRSwgeWF4cz0iciIsIGNleC5heGlzPTEuNiwgY2V4LmxhYj0xLjYsIGxhcz0xLCB4YXh0PSJuIiwgeWF4dD0ibiIsZmc9Z3JleSgwLjUpLCBmYW1pbHk9InNlcmlmIikNCg0KYXhpcygxLCBhdD1heGlzX2xhYmVsc19hdFtjKDEsMyw1LDcsOSwxMSwxMywxNSwxNywxOSwyMSwyMywyNSwyNywyOSwzMSldLCBsYWJlbHM9YXMuY2hhcmFjdGVyKDE6MzEpW2MoMSwzLDUsNyw5LDExLDEzLDE1LDE3LDE5LDIxLDIzLDI1LDI3LDI5LDMxKV0sIHRpY2s9VFJVRSwgbHR5PTEsIG1ncD1jKDMsIDEsIDApLCBsYXM9MSwgY2V4LmF4aXM9MS42LCBmb250PTEsIGNvbD1ncmV5KDAuNSksIGNvbC50aWNrcz1ncmV5KDAuMyksIGZhbWlseT0iIikNCmF4aXMoMSwgYXQ9aWRfd2VlaywgbGFiZWxzPXJlcChjKCJNb25kYXkiKSw1KSwgdGljaz1UUlVFLCBsdHk9MSwgbWdwPWMoLTEsIC0xLjIsIDApLCBsYXM9MSwgY2V4LmF4aXM9MS4zLCBmb250PTEsIGNvbD1ncmV5KDAuNSksIGNvbC50aWNrcz1ncmV5KDAuMyksIGZhbWlseT0iIikNCmF4aXMoMiwgYXQ9TlVMTCwgbGFiZWxzPVRSVUUsIHRpY2s9VFJVRSwgbHR5PTEsIG1ncD1jKDMsIDAuNywgMCksIGxhcz0xLCBjZXguYXhpcz0xLjYsIGZvbnQ9NSwgY29sPWdyZXkoMC41KSwgY29sLnRpY2tzPWdyZXkoMC4zKSkNCnRpdGxlKHhsYWI9IkRheSIsIG1ncD1jKDMsIDEsIDApLCBjZXgubGFiPTEuNiwgbGFzPTEpDQp0aXRsZSh5bGFiPSJQcm9wb3J0aW9uIG9mIGJpcnRocyBvdmVyIHRoZSBtZWFuIiwgbWdwPWMoMywgMC43LCAwKSwgY2V4LmxhYj0xLjYsIGxhcz0xKQ0KDQpsaW5lcyhpbmQsICgoZltpbmQsMV0raW50ZXJjZXB0WzFdKSpzdGRfeSttX3kpL21feSwgY29sPSJibGFjayIsIGx3ZD0zKSAgICAgICAgICAgICAgICAgCSMgZg0KYWJsaW5lKGg9MSwgbHR5PTIpCQkJCQkJCQkJCQkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbWVhbg0KbGluZXMoaW5kLCAoKGludGVyY2VwdFsxXStmMVtpbmQsMV0pKnN0ZF95K21feSkvbV95LCBjb2w9MiwgbHdkPTMpCQkJICAgICAgICAgICAgICAgICAgIyBmMSANCmxpbmVzKGluZCwgKChpbnRlcmNlcHRbMV0rZjFbaW5kLDFdK2YyW2luZCwxXSkqc3RkX3krbV95KS9tX3ksIGNvbD0zLCBsd2Q9MykJIAkJICAgICAgICAjIGYxICsgZjINCmxpbmVzKGluZCwgKGYzW2luZCwxXSpzdGRfeSttX3kpL21feSwgY29sPTQsIGx3ZD0yKQkgCSAgICAgICAgICAgICAgICAjIGYzDQpsaW5lcyhpbmQsIChmNFtkYXRhJGRheV9vZl95ZWFyMiwxXVtpbmRdKnN0ZF95K21feSkvbV95LCBjb2w9NiwgbHdkPTIpIAkJICAgICAgICAgICAgICAgICMgZjQgDQoNCmFibGluZSh2PWlkX3dlZWssIGx0eT0yLCBjb2w9ImdyZXkiKQ0KDQojbGFiZWxzIHNwZWNpYWwgZGF5cw0KdGV4dChpbmRbZGF0YV9tb250aCRtb250aD09MSZkYXRhX21vbnRoJGRheT09MV0tMC4wNSwgeSA9IDAuODQsIGxhYmVscyA9ICJOZXcgeWVhciIsIHBvcyA9TlVMTCwgb2Zmc2V0ID0gMCwgZmFtaWx5PSJzZXJpZiIsIGNleD0xLjMsIHhwZD1UUlVFLCkNCg0KbGVnZW5kKCJ0b3BsZWZ0IiwgaW5zZXQ9YygwLjEwNywwLjAwNSksIGxlZ2VuZD1jKCJPYnNlcnZhdGlvbnMiLFRlWCgnJGZfMSQnKSxUZVgoJyRmXzEgKyBmXzIkJyksVGVYKCckZl8zJCcpLFRlWCgnJGZfNCQnKSxUZVgoJyRmXzEgKyBmXzIgKyBmXzMgKyBmXzQkJykpLCBjb2w9YyhncmV5KDAuNSksMiwzLDQsNiwiYmxhY2siKSwgbHR5PWMoTkEsMSwxLDEsMSwxKSwgcGNoPWMoMjAsTkEsTkEsTkEsTkEsTkEpLCBsd2Q9YygzLDMsMywzLDMsMyksIGNleD0xLjQsIHhwZD1UUlVFLCBidHk9Im4iLCB5LmludGVyc3A9MSwgeC5pbnRlcnNwPTAuOCwgdGV4dC5mb250PTEsIG5jb2w9Miwgc2VnLmxlbj0xLjMpDQpgYGANCg0KIyMjIyBQbG90IG9mIHRoZSBmaXJzdCBmb3VyIHllYXJzDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm49RkFMU0UsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTE0LCBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQpwYXIobWFpPWMoMSwgMC44MiwgMC4xLCAwLjQyKSkNCg0KZGF0YV95ZWFyIDwtIGRhdGFbZGF0YSR5ZWFyPT0xOTY5IHwgZGF0YSR5ZWFyPT0xOTcwIHwgZGF0YSR5ZWFyPT0xOTcxIHwgZGF0YSR5ZWFyPT0xOTcyLF0NCmluZCA8LSBkYXRhX3llYXIkaWQNCmF4aXNfbGFiZWxzX2F0IDwtIGFnZ3JlZ2F0ZShkYXRhX3llYXIsIGJ5PWxpc3QoZGF0YV95ZWFyJHllYXIpLCBGVU49bWluKSRpZA0KDQpwbG90KGluZCwgKHlbaW5kXSpzdGRfeSttX3kpL21feSwgdHlwZT0icCIsIGx0eT0xLCBwY2g9MTgsIGNleD0wLjQsIGNvbD0iYmxhY2siLCB4bGFiPSIiLCB5bGFiPSJQcm9wb3J0aW9uIG9mIGJpcnRocyBvdmVyIHRoZSBtZWFuIiwgY2V4LmxhYj0xLjUsIGNleC5heGlzPTEuNiwgeGF4dD0ibiIsIHlsaW09YygwLjcsMS4zKSkNCg0KYXhpcygxLCBhdD1heGlzX2xhYmVsc19hdCwgbGFiZWxzPWMoIjE5NjkiLCIxOTcwIiwiMTk3MSIsIjE5NzIiKSwgdGljaz1UUlVFLCBjZXguYXhpcz0xLjYpDQoNCmxpbmVzKGluZCwgKChmW2luZCwxXStpbnRlcmNlcHRbMV0pKnN0ZF95K21feSkvbV95LCBjb2w9ImdyZXkiLCBsd2Q9MSkJCSAgICAjIGYNCmxpbmVzKHJhbmdlKGluZCksIGMoMSwxKSwgbHR5PTIsIGx3ZD0yKQkJCQkJCSAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1lYW4NCmxpbmVzKGluZCwgKChpbnRlcmNlcHRbMV0rZjFbaW5kLDFdKSpzdGRfeSttX3kpL21feSwgY29sPTIsIGx3ZD0xKQkJCSAgICAgICMgZjENCmxpbmVzKGluZCwgKChpbnRlcmNlcHRbMV0rZjFbaW5kLDFdK2YyW2luZCwxXSkqc3RkX3krbV95KS9tX3ksIGNvbD0zLCBsd2Q9MykJIyBmMSArIGYyDQpsaW5lcyhpbmQsIChmNFtkYXRhJGRheV9vZl95ZWFyMiwxXVtpbmRdKnN0ZF95K21feSkvbV95LCBjb2w9NiwgbHdkPTEpIAkJICAgICMgZjQNCg0KbGVnZW5kKCJ0b3BsZWZ0IiwgaW5zZXQ9YygwLjA1LDAuMDA1KSwgbGVnZW5kPWMoIk9ic2VydmF0aW9ucyIsVGVYKCckZl8xJCcpLFRlWCgnJGZfMSArIGZfMiQnKSxUZVgoJyRmXzQkJyksVGVYKCckZl8xICsgZl8yICsgZl8zICsgZl80JCcpKSwgY29sPWMoZ3JleSgwLjUpLDIsMyw2LCJncmV5IiksIGx0eT1jKE5BLDEsMSwxLDEpLCBwY2g9YygyMCxOQSxOQSxOQSxOQSksIGx3ZD1jKDMsMywzLDMsMyksIGNleD0xLjQsIHhwZD1UUlVFLCBidHk9Im4iLCB5LmludGVyc3A9MSwgeC5pbnRlcnNwPTAuOCwgdGV4dC5mb250PTEsIG5jb2w9Miwgc2VnLmxlbj0xLjMpDQpgYGANCg0KDQoNCg==